为什么派生类的构造函数要在C ++中初始化虚拟基类?

如何解决为什么派生类的构造函数要在C ++中初始化虚拟基类?

我的理解(例如,读this,是,派生类的构造函数没有调用其虚拟基类的构造函数

这是我做的一个简单示例:

class A {
    protected:
        A(int foo) {}
};

class B: public virtual A {
    protected:
        B() {}
};

class C: public virtual A {
    protected:
        C() {}
};

class D: public B,public C {
    public:
        D(int foo,int bar) :A(foo) {}
};


int main()
{
    return 0;
}

出于某种原因,构造函数B::B()C::C()试图初始化A(据我所知,D应该已经在此初始化了)点):

$ g++ --version
g++ (GCC) 10.2.0
copyright (C) 2020 Free Software Foundation,Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or fitness FOR A PARTIculaR PURPOSE.

$ g++ test.cpp
test.cpp: In constructor ‘B::B()’:
test.cpp:8:13: error: no matching function for call to ‘A::A()’
    8 |         B() {}
      |             ^
test.cpp:3:9: note: candidate: ‘A::A(int)’
    3 |         A(int foo) {}
      |         ^
test.cpp:3:9: note:   candidate expects 1 argument,0 provided
test.cpp:1:7: note: candidate: ‘constexpr A::A(const A&)’
    1 | class A {
      |       ^
test.cpp:1:7: note:   candidate expects 1 argument,0 provided
test.cpp:1:7: note: candidate: ‘constexpr A::A(A&&)’
test.cpp:1:7: note:   candidate expects 1 argument,0 provided
test.cpp: In constructor ‘C::C()’:
test.cpp:13:13: error: no matching function for call to ‘A::A()’
   13 |         C() {}
      |             ^
test.cpp:3:9: note: candidate: ‘A::A(int)’
    3 |         A(int foo) {}
      |         ^
test.cpp:3:9: note:   candidate expects 1 argument,0 provided

我敢肯定有些基本的东西我会被误解或做错了,但我不知道是什么。

解决方法

已构建虚拟库的构造器。它是有条件构造的。即,最派生类的构造函数调用虚拟基数的构造函数。如果-这是条件-具有虚拟基础的派生类不是所构造对象的具体类,则它将不会构造虚拟基础,因为它已由具体类构造。但是否则它将构建虚拟基础。

因此,您必须在所有派生类的构造函数中正确初始化虚拟基类。您只必须知道,如果具体类不是您正在编写的类,则不一定要进行特定的初始化。编译器不会也不知道您是否会创建这些中间类的直接实例,因此它不能简单地忽略它们损坏的构造函数。

如果您将这些中间类抽象化,那么编译器将知道它们永远不是最具体的类型,因此不需要初始化虚拟基的构造函数。

,

出于某种原因,构造函数B :: B()和C :: C()试图初始化A(据我所知,这时应该已经由D初始化了):

但是,如果有人单独构建C,编译器应该怎么做?最终对象D将调用A的构造函数,但是您将构造函数定义为C,这意味着可以构造它,但是构造函数出错,因为它不能构造A

,

撇开更复杂的类层次结构,对于任何派生类型,都有一个完全相同的虚拟基础副本。规则是,派生最多的类型的构造函数将以此为基础。编译器必须生成代码来处理该工作:

struct B { };
struct I1 : virtual B { };
struct I2 : virtual B { };
struct D : I1,I2 { };

B b;   // `B` constructor initializes `B`
I1 i1; // `I1` constructor initializes `B` subobject
I2 i2; // `I2` constructor initializes `B` subobject

到目前为止,这很容易想象,因为初始化的方式与B不是虚拟库的方式相同。

但是您要这样做:

D d; // which constructor initializes `B` subobject?

如果基础不是虚拟的,则I1构造函数将初始化其B主题,而I2构造函数将初始化其B子对象。但是由于它是虚拟的,所以只有一个B对象。那么哪个构造函数应该初始化它?该语言表示D构造函数对此负责。

接下来的并发症:

struct D1 : D { };
D1 d1; // `D1` constructor initializes `B` subobject

因此,在此过程中,我们创建了五个不同的对象,每个对象的虚拟基础类型为B,每个对象的B子对象都由不同的构造函数构造。

将责任放在最派生的类型上可以使初始化易于理解和可视化。可能还有其他规则,但这实际上是最简单的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?