提问人:John 提问时间:6/14/2022 更新时间:6/14/2022 访问量:382
“如果派生类没有虚拟继承基类,则必须定义所有虚拟方法”。如何以正确的方式理解这一点?
"If the deriving class does not inherit the base class virtually, then all virtual methods must be defined".How to understand that in the right way?
问:
根据 wiki,它说[强调我的]: 请注意,配额中的代码片段如下所示。
假设在基类中定义了一个纯虚方法。 如果 派生类以虚拟方式继承基类,然后继承纯类 不需要在该派生类中定义虚拟方法。 但是,如果派生类不继承基类 虚拟,则必须定义所有虚拟方法。下面的代码 可以在这里进行互动探讨。
#include <string> #include <iostream> class A { protected: std::string _msg; public: A(std::string x): _msg(x) {} void test(){ std::cout<<"hello from A: "<<_msg <<"\n"; } virtual void pure_virtual_test() = 0; }; // since B,C inherit A virtually, the pure virtual method >pure_virtual_test doesn't need to be defined class B: virtual public A { public: B(std::string x):A("b"){} }; class C: virtual public A { public: C(std::string x):A("c"){} }; // since B,C inherit A virtually, A must be constructed in each child // however, since D does not inherit B,C virtually, the pure virtual method in A *must be defined* class D: public B,C { public: D(std::string x):A("d_a"),B("d_b"),C("d_c"){} void pure_virtual_test() override { std::cout<<"pure virtual hello from: "<<_msg <<"\n"; } }; // it is not necessary to redefine the pure virtual method after the parent defines it class E: public D { public: E(std::string x):A("e_a"),D("e_d"){} }; int main(int argc, char ** argv){ D d("d"); d.test(); // hello from A: d_a d.pure_virtual_test(); // pure virtual hello from: d_a E e("e"); e.test(); // hello from A: e_a e.pure_virtual_test(); // pure virtual hello from: e_a }
如何以正确的方式理解粗体语句?
似乎如果派生类(即 )没有虚拟继承基类,那么虚拟方法可以不定义。这是我的演示代码片段,以支持我所说的:class B
#include <string>
#include <iostream>
class A {
protected:
std::string _msg;
public:
A(std::string x): _msg(x) {}
void test(){ std::cout<<"hello from A: "<<_msg <<"\n"; }
virtual void pure_virtual_test() = 0;
};
// Attention: B does not inherit A ***virtually***, the pure virtual method pure_virtual_test doesn't need to be defined, either.
class B: public A { public: B(std::string x):A("b"){} };
class D: public B {
public:
D(std::string x):B("d_b"){}
void pure_virtual_test() override { std::cout<<"pure virtual hello from: "<<_msg <<"\n"; }
};
// it is not necessary to redefine the pure virtual method after the parent defines it
class E: public D {
public:
E(std::string x):D("e_d"){}
};
int main(int argc, char ** argv){
D d("d");
d.test();
d.pure_virtual_test();
E e("e");
e.test();
e.pure_virtual_test();
}
答:
维基百科文章中的描述是错误的/误导性的。
“如果派生类不以虚拟方式继承基类,则必须定义所有虚拟方法”仅在派生类被实例化时才为 true。没有实例化的声明不需要定义纯虚拟方法。
维基百科文章声称“由于 D 不以虚拟方式继承 B,C,因此必须定义 A 中的纯虚方法”是根本不正确的,下面的编译没有任何问题,没有实例化纯虚方法:D
E
#include <string>
#include <iostream>
class A {
protected:
std::string _msg;
public:
A(std::string x): _msg(x) {}
void test(){ std::cout<<"hello from A: "<<_msg <<"\n"; }
virtual void pure_virtual_test() = 0;
};
// since B,C inherit A virtually, the pure virtual method pure_virtual_test doesn't need to be defined
class B: virtual public A { public: B(std::string x):A("b"){} };
class C: virtual public A { public: C(std::string x):A("c"){} };
class D: public B,C {
public:
D(std::string x):A("d_a"),B("d_b"),C("d_c"){}
};
class E: public D {
public:
E(std::string x):A("e_a"),D("e_d"){}
};
int main()
{
return 0;
}
main
留空,并声明没有问题。现在,如果你试图实例化一个或另一个,那么你就会遇到问题。D
E
评论
引用的文本似乎指的是一种称为支配的规则,这导致了一种情况,即它看起来就像一个虚拟函数没有被覆盖,即使它被覆盖了。下面是一个示例:
struct base {
virtual void f();
};
struct i1 : base {
// doesn't override base::f
};
struct i2 : base {
void f() {} // overrides base::f
struct derived : i1, i2 {
};
使用此层次结构,您可以编写
derived d;
d.f(); // illegal, because ambiguous:
// i1::f, inherited from base, or i2::f
i1* p = &d;
p->f(); // calls base::f
很简单,对吧?现在让我们从 virtual 进行继承。这就是主导地位发挥作用的地方:base
struct base {
virtual void f();
};
struct i1 : virtual base {
// doesn't override base::f
};
struct i2 : virtual base {
void f() {} // overrides base::f
struct derived : i1, i2 {
};
现在只有一个子对象,并且覆盖 ,即使在 :base
i2::f
base::f
i1
derived d;
d.f(); // calls i2::f
i1* i1p = &d;
i1p->f(); // calls i2::f
是的,调用调用的 的版本,即使对 一无所知。只是因为 和 都是 的基类,并且都具有虚拟基,这才起作用。编译器必须为这种跨层次结构调用获取正确的代码。i1p->f()
i2
f
i1
i2
i1
i2
derived
base
制作纯粹的虚拟并不会改变寻找其超凡者的规则。所以对于非虚拟继承,不会覆盖,并且是一个抽象类。但是对于虚拟继承,覆盖,并且类不是抽象的。base::f
i1
base::f
derived
i2::f
base::f
derived
评论
class B