C++创建派生类对象时,调用构造函数顺序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++创建派生类对象时,调用构造函数顺序相关的知识,希望对你有一定的参考价值。

#include<iostream>
using namespace std;
class Base
public:
Base()cout<<'A';
Base(int c)cout<<c;
~Base()cout<<"基类析构";
;
class Derived:public Base
public:
Derived()cout<<'B';
Derived(int c)cout<<c;
~Derived()cout<<"派生类析构";
;
int main()

int i = 9;
Derived d1(i);
return 0;

为什么先调用基类的默认构造函数,而不是自定义的构造函数?
删掉基类的默认构造函数后,编译出错,说没有默认构造函数,那在有自定义构造函数的情况下。一定需要显式的默认构造函数吗?
运行结果是

A9派生类析构基类析构

    派生类构造函数中的某些初始化可能是基于基类的,所以规定构造在类层次的最根处开始,而在每一层,首先调用基类构造函数,然后调用成员对象构造函数。因为C++的成员变量是不会自动初始化的。

    如果没有显式调用基类的构造函数,会自动调用基类的无参构造函数。而如果基类只有带参数的构造函数,则会报错。不一定要显式的无参构造函数,可以显式调用基类带参数的构造函数。

#include<iostream>
using namespace std;
class Base
public:
    Base(int c)cout<< "基类带参构造函数" << c << endl;
~Base()cout<<"基类析构" << endl;
;
class Derived:public Base
public:
    Derived(int c):Base(c) // 显式调用基类构造函数
    
     cout<< "派生类带参构造函数" << c << endl;

~Derived()cout<<"派生类析构" << endl;
;
int main()

    int i = 9;
    Derived d1(i);
    return 0;

输出结果:

基类带参构造函数9

派生类带参构造函数9

派生类析构

基类析构

参考技术A 因为class Derived: public Base 继承关系。
在子类构造时会调用父类构造函数,也可以手动指定:
Derived(int c):Base()//或
Derived(int c):Base(c)//此时可以删掉基类默认构造函数。
cout<<c;

C++如何使用派生类构造函数销毁基类中的对象

【中文标题】C++如何使用派生类构造函数销毁基类中的对象【英文标题】:C++ how to destroy an object in the base class with a derived class constructor 【发布时间】:2015-06-13 22:03:02 【问题描述】:

所以在我的程序中,我有一个名为 hangman 的派生类和一个名为 HangmanGraphics 的派生类。我遇到的问题是在游戏结束后我想重置我的变量,但由于某种原因,我的基本构造函数没有重新启动,甚至没有被调用。当我运行程序时,它将转到基本构造函数一次,但在程序结束时:

#include "player.h"
#include "hangman.h"
#include "HangmanGraphics.h"

using namespace std;

int main()


    HangmanGraphics game2;
    while(1)
    
        game2.Play();

        if(game2.Play()=='Y')
        
            game2=HangmanGraphics();

            //in this part of the code I want to reset my base
            //constructor values but how do I do that by using the 
            //derived construtor  

            continue;
        
    

【问题讨论】:

你的派生ctor是否调用基础ctor? @AmiTavory 当我运行程序时,即使我没有在派生构造函数的主体中添加任何内容,也会调用基础构造函数,但是在我通过 continue 之后,永远不会调用基础构造函数 【参考方案1】:

便宜的黑客。将 game2 的定义移到 while 循环中,每次循环都会提供一个新的 game2:

int main()

    while(1)
    
        HangmanGraphics game2; // game2 created here
        // do stuff
     // game2 destroyed here

您的问题中没有提供足够的信息来说明这是好事还是坏事。但是……

game2=HangmanGraphics();

会做五件事:

    调用 HangmanGraphics 的构造函数来创建一个临时的 HangmanGraphics。 这会导致调用 Hangman 的构造函数 调用 HangmanGraphics 的 = 运算符。如果未指定,则默认将右手 HangmanGraphics 的内容复制到左侧。它会复制一个指针,但不会复制指向的数据。 在临时 HangmanGraphics 上调用析构函数 这会导致调用 Hangman 的析构函数

如果您在 HangmanGraphics 或 Hangman 中有任何动态分配的存储,您需要阅读 Rule of Three

在临时 HangmanGraphics 中动态分配的任何内容及其基础 Hangman 都将(或应该已经)被析构函数删除。如果未自定义 operator= 来处理动态数据,则 game2 现在包含指向无效存储的指针。

例子:

class base

public:
    base(): baseval(number++), interestingData(new int(number++))
    
        cout << "base ctor " << baseval << "," << * interestingData <<endl;
    
    virtual ~base()
    
        cout << "base dtor " << baseval << "," << * interestingData <<endl;
        delete interestingData;
    
private:
    int baseval;
    int * interestingData;
;

class derived: public base

public:
    derived():base()
    
        cout << "derived ctor" <<endl;
    
    virtual ~derived()
    
        cout << "derived dtor" <<endl;
    
    derived & operator=(const derived & rhs) //only exists to do the cout
    
        cout << "derived =" <<endl;
        base::operator=(rhs);
        return *this;
    
;

int main()

    derived test;
    cout << "created test" << endl;
    test = derived();
    cout << "exit" << endl;

输出

base ctor 0,1
derived ctor
created test
base ctor 2,3
derived ctor
derived =
derived dtor
base dtor 2,3
exit
derived dtor
base dtor 2,4067440

最后一次打印中的interestingdata 被破坏,因为它指向的地址已被重新分配。更有趣的是,它即将被第二次删除,这会让你的程序崩溃。

【讨论】:

以上是关于C++创建派生类对象时,调用构造函数顺序的主要内容,如果未能解决你的问题,请参考以下文章

C++中派生类的构造函数怎么显式调用基类构造函数?

c++派生类构造顺序

C++ 基类,子对象,派生类构造函数调用顺序

C++中,建立子类对象的时候,会调用基类的构造函数,

C++入门派生类和基类的构造/析构函数关系

派生类的构造函数与析构函数的调用顺序