如何正确获得虚拟继承?

How do I get virtual inheritance right?

本文关键字:继承 虚拟 何正确      更新时间:2023-10-16

在下面的示例中,我有我的父类和两个子类。任一子项的对象都存储在父项的向量中。循环向量,我只看到来自父类的方法调用。

如何正确定义方法和表,以及如何避免切片效应。我已经做Python太久了,这样的东西可以工作。

#include <iostream>
#include <vector>

using namespace std;
class A{
public:
virtual string print(){return string("A");};
};
class B: public A{
virtual string print() final {return string("B");};
};
class C: public A{
virtual string print() final {return string("C");};
};
int main()
{
vector<A> v;
v.push_back(B());
v.push_back(C());
for(auto x : v){
cout << x.print() << endl;
}
}

=>

$g++ -std=c++11 -o main *.cpp
$main
A
A

让我们看看你的代码:

vector<A> v;
v.push_back(B());
v.push_back(C());

在这里,push_back接受类型A&&的参数,并使用A的移动构造函数移动它来构造向量的新元素。因此,您的代码:

  1. 创建A秒的向量
  2. 构造B的实例,然后在该B实例上调用A的移动构造函数以在向量中构造A的实例(不是B的实例(
  3. C做同样的事情,而不是B

如果要使用动态调度,则需要在向量中存储指向元素的指针。分配堆上的对象并使用std::unique_ptr保留对它们的句柄,这将在其析构函数中释放内存。

// for std::unique_ptr, available since C++11, and std::make_unique, available since C++14
#include <memory>
// ...
std::vector<std::unique_ptr<A>> v;
v.push_back(std::make_unique<B>());
v.push_back(std::make_unique<C>());

现在向量使用std::unique_ptr,在遍历向量时需要使用&

for(auto& x : v) {
std::cout << x->print() << std::endl;
}

auto不会自动放置引用。如果只用auto,那么向量的每个元素都会被复制到x中,但是因为std::unique_ptr的复制构造函数被删除了,代码就不会编译。

任一子对象的对象都存储在父级的向量中。

不。父向量只能存储父对象。父对象不是子对象。

循环向量,我只看到来自父类的方法调用。

这是因为向量包含父对象。

如何正确定义方法和表列表

成员函数定义或 vtables 没有任何问题。

以及如何避免切片效应。

您可以通过不将基本子对象与派生对象切下来来避免切片效果。动态多态性只能通过间接实现。使用指针(或引用(,您可以指向基对象,该对象可能是不同派生对象的基子对象。例:

B b;
C c;
A* a;
a = &b;
a->print(); // dynamic dispatch invokes B::print
a = &c;
a->print(); // dynamic dispatch invokes C::print
A sliced = b;
sliced.print(); // static dispatch invokes A::print
// sliced is an individual object that is not
// base sub object of another