首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

为什么超类空构造函数是必需的,但在可怕的菱形情况下却没有调用?

超类空构造函数是必需的,是因为在子类中创建对象时,需要先调用超类的构造函数来完成超类的初始化工作。超类的构造函数负责初始化超类的成员变量和执行超类的其他初始化操作。如果没有超类的构造函数,子类无法正确地初始化超类的成员变量,导致程序出错。

然而,在可怕的菱形情况下,子类继承了两个或多个具有相同超类的类,这些类之间存在继承关系,形成了一个菱形的继承结构。在这种情况下,如果每个类都调用超类的构造函数,就会导致超类的初始化工作被重复执行多次,造成资源浪费和逻辑混乱。

为了解决这个问题,编程语言引入了虚拟继承的概念。虚拟继承可以确保在菱形继承结构中,只有一个共同的超类对象被创建,避免了重复初始化的问题。在虚拟继承中,只有最远的派生类负责调用超类的构造函数,其他派生类则通过调用构造函数的方式间接初始化超类的成员变量。

总结起来,超类空构造函数是必需的,用于初始化超类的成员变量和执行超类的其他初始化操作。在可怕的菱形情况下,不调用超类的构造函数是为了避免重复初始化和资源浪费。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

创建子类对象时,父类构造函数调用被子类重写方法为什么调用子类方法?

public static void main(String[] args) { A a = new A(); B b = new B(); } } 问题:为什么创建...A对象时候父类会调用子类方法?...但是:创建B对象父类会调用父类方法? 答案: 当子类被加载到内存方法区后,会继续加载父类到内存中。...当子类对象创建时,会先行调用父类构造方法(构造方法也是方法),虚拟机会在子类方法区寻找该方法并运行。 但是:由于java语言静态多分派,动态单分派。...其结果当编译时候,父类构造方法调用方法参数已经强制转换为符合父类方法参数了。 上边代码在编译前已经转换为下面这个样子了。

6.1K10

C++重要知识点小结---2

如果基类中函数函数,当使用指针或引用访问对象时,将基于实际运行时指针所指向对象类型来调用派生类函数。...这说明:空类所占空间为1,单一继承类空间也为1,多重继承类空间还是1.但是虚继承涉及到虚表(虚指针),所以sizeof(C)大小为4 4.多继承构造顺序 构造对象规则需要扩展以控制多重继承...构造函数按下列顺序被调用: 任何虚拟基类构造函数按照它们被继承顺序构造; 任何非虚拟基类构造函数按照它们被继承顺序构造; 任何成员对象构造函数按照它们声明顺序调用; 类自己构造函数。...纯虚函数 C++纯虚函数用于表示一个类不能被创建实例, 必需子类覆盖该方法定义后,方可新建类实例,格式在虚函数后面添加 = 0。...,指向Circle或者Square 一个有意思问题:为什么析构函数要设置成虚函数 Range *r1 = new Circle(3, 4); 如果析构函数不是虚函数,则r1在释放内存时,则调用提Range

70770
  • C++重要知识点小结---2

    如果基类中函数函数,当使用指针或引用访问对象时,将基于实际运行时指针所指向对象类型来调用派生类函数。...这说明:空类所占空间为1,单一继承类空间也为1,多重继承类空间还是1.但是虚继承涉及到虚表(虚指针),所以sizeof(C)大小为4 4.多继承构造顺序 构造对象规则需要扩展以控制多重继承...构造函数按下列顺序被调用: 任何虚拟基类构造函数按照它们被继承顺序构造; 任何非虚拟基类构造函数按照它们被继承顺序构造; 任何成员对象构造函数按照它们声明顺序调用; 类自己构造函数。...纯虚函数 C++纯虚函数用于表示一个类不能被创建实例, 必需子类覆盖该方法定义后,方可新建类实例,格式在虚函数后面添加 = 0。...,指向Circle或者Square 一个有意思问题:为什么析构函数要设置成虚函数 Range *r1 = new Circle(3, 4); 如果析构函数不是虚函数,则r1在释放内存时,则调用提Range

    81270

    C++:继承与派生

    (但是有些情况下不可避免,后面会说) 四、派生类默认成员函数 6个默认成员函数,“默认”意思就是指我们不写,编译器会变我们自动生成一个,那么在派生类中,这几个成员函数如何生成呢?...派生类构造函数必须调用基类构造函数初始化基类那一部分成员。如果基类没有默认构造函数,则必须在派生类构造函数初始化列表阶段显示调用。 2....派生类拷贝构造函数必须调用基类拷贝构造完成基类拷贝初始化。 3. 派生类operator=必须要调用基类operator=完成基类复制。...(3)析构函数一般情况想不用写,但在后续一些场景析构函数需要构成重写,重写条件之一函数名相同(涉及到虚函数)。...因为这涉及到先有鸡还是先有蛋问题,我们不创建对象就调用不了这个函数,但是要调用这个函数又需要一个对象,所以为了解决这个问题,只能将该函数变成静态成员函数,这样我们可以通过类限定符去访问他 七、复杂菱形继承及菱形虚拟继承

    13610

    python 多重类继承__init__

    目的 项目中遇到多重类继承问题,想调用父类构造函数内容,调试了一两个小时,遇到两个问题。...说不存在某个父类函数; 报MRO列表错误; 查询了相关文档,大致讲解父类继承,没有涉及到多重继承,以及多重继承构造函数问题,这里总结一下。...调用父类方法 想在子类中调用父类某个已经被覆盖方法: 解决方案 为了调用父类(类)一个方法,可以使用 super() 函数,比如 class A: def spam(self):...其实,在上面的情况下,super 获得类刚好父类,但在其他情况就不一定了,super 其实和父类没有实质性关联。...总结 事实上,super 和父类没有实质性关联; super(cls, inst) 获得 cls 在 inst MRO 列表中下一个类; 在使用多重继承时候,注意继承顺序; 如果使用到父类构造函数

    1.1K10

    C++反汇编第五讲,认识多重继承,菱形继承内存结构,以及反汇编中表现形式.

    main函数我们得知,我们生成了一个孩子类对象.此时按照C/C++规范,应该先从左往右依次构造父类1,父类2 此时情况和我们昨天所讲单继承里面,包含一个成员一样.但是有不同之处 1.在子类自身构造中会复写两次虚表...(和构造相反) 二丶菱形继承 1.普通菱形继承讲解   普通菱形继承,为什么说普通.请看高级代码 高级代码: class CGrandFather //新添加爷爷类 { public:...通过第普通菱形继承,我们得出了每一个父类都会有一个父类(爷爷类)然后产生了相同数据,且数据不明确必须指明调用,所以C++为了解决这种问题,出了一个虚继承. 直接贴上来内存结构: ?...有人说,为什么爷爷类会放在下面.而不是上面,视编译器而定,也可以放在上面.为什么放在上面说来话长,不符合此博客篇幅. 提示一句:把自己当做编译器.    根据构造时候先父类构造我们得出了....看其反汇编代码: 1.main函数构造 ? 看出一个特征,push 1了,为什么?

    79770

    继承

    如果基类中有默认成员函数,当派生类中不显示调用时候,会自动调用。 对于构造函数,都会在初始化列表时候自动调用基类构造函数。...这样才能保证先析构派生类,再析构基类 构造函数 1.当基类有默认构造函数时候,可以只初始化派生类新成员变量,也可以自己调用基类默认构造,看自己心情。...2.当基类没有默认构造函数时候,必须自己要写构造函数调用基类 派生类构造函数先初始化基类,再初始派生类中成员 静态成员变量不属于具体类对象,属于该类所有对象。...,那么上面的代码就会报错 此时B就应该在初始化列表显示调用A中构造函数。...菱形继承与菱形虚拟继承 菱形继承 什么菱形继承? 如下图:B继承了A,C也继承了A,D既继承了B也继承了C。这种继承关系就是菱形继承 为什么会出现菱形继承?

    24740

    年后跑路第一战,从Java泛型学起!

    本文章对 Java 中泛型快速介绍,包含泛型背后目标以及使用泛型如何提高我们代码质量。 为什么要引入泛型?...泛型方法 对于泛型方法,我们可以用不同类型参数调用它们。编译器将确保我们使用任何类型正确性。 泛型方法属性: 泛型方法在方法声明返回类型之前有一个类型参数(包含类型菱形运算符)。...即使该方法返回 void,这也是必需。 如前所述,该方法可以处理多个泛型类型。在这种情况下,我们必须将所有泛型类型添加到方法签名中。...,该函数将具有T类型元素数组转换为具有G类型元素列表。...首先,我们知道Object所有 Java 类类。但是,Object集合不是任何集合类型。

    70530

    C++之继承

    protected成员不能在类外直接访问,但在派生类中可以被访问。 基类成员在子类中访问方式==Min(成员在基类访问限定符,继承方式)。...但是一般情况下显示写出继承方式比较好。 实际运用中大部分都是public继承,很少有protected/private继承。...函数并不构成重载,因为他们在不同作用域,他们隐藏关系 四、派生类默认成员函数 1.构造函数 派生类构造函数必须调用基类构造函数初始化基类那一部分成员,如果基类没有默认构造函数,派生类就必须在初始化列表处显示调用基类构造函数...派生类对象初始化时,会先调用基类构造函数,再调用派生类构造函数。 2.拷贝构造 必须调用基类拷贝构造完成基类部分拷贝构造。...4.析构函数 派生类额析构函数会在调用结束后自动调用基类析构函数清理基类成员,确保先清理派生类成员再清理基类成员析构顺序。 派生类对象析构先调用派生类析构函数调用基类析构函数

    40910

    Java继承与接口机制

    C++对此问题解决办法与实现多继承解决办法相同,仍然要求在有歧义时消除歧义. 3.构造函数执行顺序 构造函数很重要很特殊函数,意义不言而喻....多继承机制下,复杂继承关系下,一个类实例化时构造函数执行顺序难以处理....出于自由性和可用性考虑,一个类对于父类构造函数执行顺序应该拥有指定机制(C++就是用继承声明顺序来指定构造函数执行顺序),然而复杂情况下,程序员仍旧难以理解整个实例化过程中构造函数执行顺序,容易出错...上面提到多继承机制实现多继承、成员命名冲突、构造函数执行顺序等问题在菱形继承等环境下更为复杂....同样都是先以规则确定菱形继承情况下继承树,然后从继承树由下往上,最高优先级不唯一时报错.

    40430

    【Java】继承

    如图所示: 其中,多个类可以称为 子类 ,单独那一个类称为 父类 、 类( superclass ) 或者 基类 。...子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样。 5. 继承后特点——构造方法 当类之间产生了关系,其中各类中构造方法,又产生了哪些影响呢?...首先我们要回忆两个事情,构造方法定义格式和作用。 1. 构造方法名字与类名一致。所以子类无法继承父类构造方法。 2. 构造方法作用是初始化成员变量。...代码 体现在子类构 造方法调用时,一定先调用父类构造方法。...访问构造方法 子类每个构造方法中均有默认 super() ,调用父类空参构造。手动调用父类构造会覆盖默认 super() 。

    79320

    【C++】从零开始认识继承

    ,内置类型会不处理,自定义类型会调用构造函数。...析构函数可以主动调用。...总结 派生类默认成员函数注意事项: 派生类构造函数必须调用基类构造函数初始化基类那一部分成员。如果基类没有默认构造函数,则必须在派生类构造函数初始化列表阶段显示调用。...派生类拷贝构造函数必须调用基类拷贝构造完成基类拷贝初始化。 派生类operator=必须要调用基类operator=完成基类复制。...派生类析构函数会在被调用完成后自动调用基类析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员顺序。 派生类对象初始化先调用基类构造再调派生类构造

    7110

    C++继承(多继承、菱形继承?)

    但是一般情况下编译器会自己帮我们去调用父类析构函数,所以无需我们在子类析构函数调用父类析构函数!(后面会讲) Ⅴ....1、派生类构造函数 ① 父类成员需调用自己构造完成初始化。 即子类构造函数必须调用父类构造函数初始化父类那一部分成员。...② 如果 父类没有默认构造函数(也就是有父类有自己写需要传值构造函数),则必须在子类构造函数初始化列表阶段显式调用。 ③ 子类对象初始化先调用父类构造再调子类构造。...message : “B::B(void)”: 由于基类调用已删除或不可访问函数“A::A(void)”,因此已隐式删除函数 父类 A 构造函数私有化后 B 就无法构造对象,因为 B 构造函数必须要调用...2、派生类拷贝构造函数 派生类拷贝构造函数必须调用基类拷贝构造完成基类拷贝初始化。

    2K20

    【C++】继承

    派生类默认成员函数 派生类默认成员函数规则如下: 1、派生类构造函数必须调用基类构造函数初始化基类那一部分成员。...如果基类没有默认构造函数,则必须在派生类构造函数初始化列表阶段显示调用基类构造函数。 2、派生类拷贝构造函数必须调用基类拷贝构造完成基类拷贝初始化。...,所以我们需要在子类构造函数初始化列表处显式调用父类构造来完成父类成员初始化; (2)子类拷贝构造必须调用父类拷贝构造完成对父类成员拷贝,同时这里还存在子类对象赋值给父类对象 (切片) 问题...传统做法将类构造私有,因为子类对象在进行构造时必须调用父类构造函数完成父类成员初始化工作,同时父类私有成员在子类中不可访问,所以子类无法调用父类构造,自然也就无法创建子类对象。...上面这种 C++98 给出做法,它虽然阻止了子类创建对象,但是构造私有化也使得它本身也不能创建对象,因为创建对象需要调用构造函数

    87800

    java_static、final、super、this关键字使用

    在使用过程中,主要目的还是想在不创建对象情况下,去调用方法 final关键字 final: 可以用于修饰类、方法和变量。 类:被修饰类,不能被继承。 方法:被修饰方法,不能被重写。...子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样。 继承后构造方法特点 构造方法名字与类名一致。所以子类无法继承父类构造方法构造方法作用是初始化成员变量。...继承后子类构造方法特点:子类所有构造方法都会调用父类无参构造类空间优先于子类对象产生 在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。...目的在于子类对象中包含了其对应类空间,便可以包含其父类成员,代码体现在子类构造方法调用时,一定先调用父类构造方法。理解图解如下: ?...手动调用父类构造会覆盖默认super()。 super() 和 this() 都必须构造方法第一行,所以不能同时出现。 Java只支持单继承,不支持多继承。

    39930

    【C++修炼之路】15.C++继承

    _name; // 姓名 }; 下面就开始探讨: 4.1 派生类构造函数 派生类不写构造函数,不会报错: 如果将基类构造函数去掉,派生类不写默认成员函数就会报错,因为派生类调用父类构造函数。...发现顺序: 构造: 基类先构造,派生类后构造。 析构: 派生类先析构,基类后析构。 4.5 总结 派生类构造函数必须调用基类构造函数初始化基类那一部分成员。...如果基类没有默认构造函数,则必须在派生类构造函数初始化列表阶段显示调用。 派生类拷贝构造函数必须调用基类拷贝构造完成基类拷贝初始化。...那么编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数不加virtual情况下,子类析构函数和父类析构函数构成隐藏关系。...那为什么普通菱形继承没有这个偏移量呢?因为普通菱形继承不会优化成一个A,这也就代表每一个A都有一个对应值,他们并不相同,因此不需要通过各种作用域去访问同一个A,每一个作用域都有属于自己A。

    53600

    【C++】三大特性之继承

    int main() { Student s1; s1.Person::Print(); return 0; } ---- 四、派生类默认成员函数 派生类构造函数必须调用基类构造函数初始化基类那一部分成员...如果基类没有默认构造函数,则必须在派生类构造函数初始化列表阶段显示调用。 派生类拷贝构造函数必须调用基类拷贝构造完成基类拷贝初始化。...那么编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数不加virtual情况下,子类析构函数和父类析构函数构成隐藏关系 代码: #include ...name时候,我们需要用到Person构造函数,因为我们没有默认构造函数,所以我们需要在初始化列表里面显式调用。  ...补充: 同样,我们看下面这段代码: 因为类中函数存储在代码段,所以调用函数也是不需要解引用对象获取,这里对象作用也是传递一个this指针。

    35720

    搞清楚,易如反掌。(暑假提升-继承专题)

    需要注意!这里隐蔽而不是函数重载,重载和隐蔽两码事! 2、5、派生类默认成员函数 派生类构造函数必须调用基类构造函数初始化基类那一部分成员。...如果基类没有默认 构造函数,则必须在派生类构造函数初始化列表阶段显示调用。 派生类拷贝构造函数必须调用基类拷贝构造完成基类拷贝初始化。...派生类operator=必须要调用基类operator=完成基类复制。 派生类析构函数会在被调用完成后自动调用基类析构函数清理基类成员。...因为这样才能保证派生类对象先清理派生类成员再清理基类成员顺序。 派生类对象初始化先调用基类构造再调派生类构造。 派生类对象析构清理先调用派生类析构再调基类析构。...那么编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数不加 virtual情况下,子类析构函数和父类析构函数构成隐藏关系。 构造时,基类构造再到派生类。

    7210

    【C++】继承

    派生类构造函数只能调用基类构造函数来初始化基类那部分成员,不能在自己构造函数里面初始化基类成员,值得注意,如果基类有默认构造函数,那我们不需要管基类成员初始化工作,只要把派生类自己成员在构造函数里面初始化即可...拷贝构造函数构造不同,必须在派生类拷贝构造初始化列表处显示调用基类拷贝构造,完成基类成员复制。在传参时有人可能会有疑问,调用基类拷贝构造该如何将子类中基类成员提取出来呢?...派生类对象初始化时,先调用基类构造调用子类构造,在析构时与栈结构相同,先调用子类析构函数,在子类析构函数调用完毕时,编译器会自动调用基类析构函数。...,父类成员会默认调用父类构造函数完成初始化。...为什么菱形继承一个大坑呢?

    69410
    领券