C++ C++;

C++ C++;,c++,inheritance,C++,Inheritance,假设我有以下课程: class A { }; class B : public A { }; class C : public A { }; class BaseClass { public: virtual void dummy(A* a) = 0; }; class DerivedClass1 : public BaseClass { public: void dummy(B* b); }; class DerivedClass2 : public BaseClas

假设我有以下课程:

class A {
};

class B : public A {
};

class C : public A {
};

class BaseClass {
public:
    virtual void dummy(A* a) = 0;
};

class DerivedClass1 : public BaseClass {
public:
    void dummy(B* b);
};

class DerivedClass2 : public BaseClass {
public:
    void dummy(C* c);
};
正如您看到的
B
C
继承自
A
DerivedClass1
DerivedClass2
继承自
BaseClass

根据我的理解,这种函数声明
dummy()
是不允许的,因为参数已经更改,即使
B
C
是从
A
派生的

正确的方法是什么

一种可能是将参数保留在
基类中,然后在
dummy
函数中进行强制转换,但我想这不是很好


否则,只需不派生
dummy
(并将其从
BaseClass
中删除),因此这两个类
DerivedClass1
DerivedClass2
都独立声明它们。但是从
BaseClass
派生的所有类都必须实现dummy的想法就没有了。

首先,当声明某个
A
B
C
的基类时,您这样做的目的是使
B
C
具有
A
的所有属性,并且您可以在中使用
A
的任何位置使用
B
C
。一个好的设计通常为
A
提供一个有意义的定义,允许对
A
的所有专门化进行
dummy
的一般定义。从这个意义上讲,这个问题可能没有你想象的那么普遍

如果你想实例化
DerivedClass1
DerivedClass2
,你的
DerivedClass1
DerivedClass2
的概念实际上没有意义,因为为了成为
基类
,它们必须提供一个有意义的
无效虚拟(a*a)
定义。你必须提供这个定义。它们可以提供额外的方法
void dummy(B*B)
void dummy(C*C)
,但这些方法仅在
基类
实现的静态类型为
DerivedClass1
DerivedClass2
时使用

如果
DerivedClass1
DerivedClass2
需要区分
B
C
,这可能是设计不良的标志。但这也可能是一个明智的决定。通常,您需要一种方法来动态地分派到正确的方法。例如,这可以通过以下方式实现:

class DerivedClass1 : public BaseClass
{
    virtual void dummy( A * a ) override {
        if( dynamic_cast<B*>( a ) != nullptr ) {
            dummy( dynamic_cast<B*>( a );
        }
        else if( dynamic_cast<C*>( a ) != nullptr) {
            dummy( dynamic_cast<C*>( a );
        }
        else
        {
            // ...
        }
    }

    void dummy( B * );
    void dummy( C * );
};
class-DerivedClass1:公共基类
{
虚拟无效虚拟(A*A)覆盖{
如果(动态_cast(a)!=nullptr){
假人(动态铸型(a);
}
否则如果(动态_cast(a)!=nullptr){
假人(动态铸型(a);
}
其他的
{
// ...
}
}
虚空假人(B*);
空洞假人(C*);
};
根据我的理解,这种函数dummy()的声明是不允许的

从技术上讲,所显示的
dummy
声明是允许的。但可能是您希望孩子们是具体的,而事实并非如此

否则,只需不派生dummy(并将其从基类中移除),这样DerivedClass1和DerivedClass2两个类都独立声明它们

这种方法是有道理的

但是,从基类派生的所有类都必须实现dummy的想法就消失了

这只是一个不能通过继承基类来表达的想法。没有“child使用某个参数实现成员函数”的概念。参数类型必须是已知的,并且所有子级必须接受基类接受的所有参数。这不是由层次结构实现的,因此子级保持抽象


您正在寻找的结构似乎是概念。C++20将引入一种编程方式来指定概念;在此之前,概念是隐式的:如果您编写模板,您可以指定类型参数必须满足成员函数
dummy
的要求类型将满足这个概念。

虚拟继承的要点是,您可以通过对基类型的引用/指针来调用派生类:

BaseClass* p = some_factory();
因此,在调用
p.dummy(…)
时,您(不一定)知道指针后面的运行时类型。因此,您无法明智地决定是否必须向其传递
A
B
C
实例

这就是为什么您必须匹配声明类型,并在重写函数中找出您拥有的实际对象

  • static\u cast
    :如果您确信调用者将向您传递正确的运行时类型
  • dynamic\u cast
    :如果不这样做,则会导致运行时成本和要求rtti
  • 您的
    A
    类型具有虚拟成员函数,您只需通过
    A*
    参数调用即可
例如:

void DerivedClass1::dummy(A* a) {
  if (B* const b = dynamic_cast<B*>(a)) {
    /* do stuff with b */
  } else {
    /* error handling -> wrong runtime type */
  }
}
void-DerivedClass1::dummy(A*A){
如果(B*常数B=动态(a)){
/*和b一起做事*/
}否则{
/*错误处理->错误的运行时类型*/
}
}

C++无法处理您的情况,因为无法对基类的函数调用施加此类约束。但是可以更改虚拟函数的类型,例如,对于返回的类型,请参阅:

类基类{
公众:
虚空剂量(A*)=0;
虚拟A*虚拟(A*)=0;
};
类DerivedClass1:公共基类{
公众:
void dosomething(A*A){B*B=dummy(A);做某事;}
//请参见返回类型是A*但现在是B*
B*虚拟(A*A){返回动态_cast(A);}
};

你的问题到底是什么?那不是继承的目的。如果你有
BaseClass*
somewhe
class BaseClass {
public:
    virtual void dosomething(A*) = 0;
    virtual A* dummy(A*) = 0;
};

class DerivedClass1 : public BaseClass {
public:
    void dosomething(A* a) {B* b = dummy(a); do something;}
    //See return type was A* but now is B*
    B* dummy(A* a) { return dynamic_cast<B*>(a); }
};