C++理解继承中的构造函数

C++ understanding constructors in inheritance

我目前正在学习 C++,想了解构造函数在继承的上下文中是如何工作的。这是我的 parent 和 child classes:

#include <iostream>
#include <string>

enum COLOR { Green, Blue, White, Black, Brown, };


class Animal
{
    protected:
        std::string _name;
        COLOR _color;
    public:
        Animal(): _name("unknown"){
            std::cout << "constructing Animal object " << _name << std::endl;
        }
        Animal(std::string animalName, COLOR animalColor){
            _name = animalName;
            _color = animalColor;
            std::cout << "constructing ";
            std::cout<< _color;
            std::cout << " Animal object " << _name << std::endl;
        }
        ~Animal(){
            std::cout << "destructing Animal object " << _name << std::endl;
        }
        void speak(){
            std::cout << "Animal speaks" << std::endl;
        }
        void move() const {}
    private:
};
class Mammal: public Animal{
    public:
        Mammal():Animal(){}
        Mammal(std::string mammalName, COLOR animalColor)
        :Animal(mammalName, animalColor){}
        ~Mammal(){
            std::cout << "Destructing Mammal object " << _name << std::endl;
        }
        void eat() const{
            std::cout << "Mammal eat" << std::endl;
        }

    private:
};

class Dog: public Mammal{
    public:
        Dog():Mammal(){}
        Dog(std::string dogName, COLOR dogColor)
            :Mammal(dogName, dogColor){}
        ~Dog(){
            std::cout << "Destructing Dog object " << _name << std::endl;
        }

    private:


};

这是我的主要内容:

 int main(){

    Animal a;
    a.speak();

    Animal b("Boar", Blue);
    b.speak();

    Mammal m("Monkey", Black);
    m.speak();

    Dog d("Panda", Brown);
    std::cout << "Program exiting..." << std::endl;
    return 0;
}

输出结果如下:

constructing Animal object unknown
Animal speaks
constructing 1 Animal object Boar
Animal speaks
constructing 3 Animal object Monkey
Animal speaks
constructing 4 Animal object Panda
Program exiting...
Destructing Dog object Panda
Destructing Mammal object Panda
destructing Animal object Panda
Destructing Mammal object Monkey
destructing Animal object Monkey
destructing Animal object Boar
destructing Animal object unknown

Process returned 0 (0x0)   execution time : 1.102 s

我很好奇的是析构函数语句。似乎如果我向 subclass 添加一个析构函数(同样似乎也适用于构造函数),你会看到 subclass 的析构函数运行,然后是 parent class 也运行。 因此你的析构函数顺序为 Dog -> Mammal -> Animal。这是什么意思? 这是否意味着 C++ 已经初始化了 3 个实例 objects 只是为了制造 1 个 Dog object?这里的析构函数(和构造函数)流程是如何工作的?

Does this mean that C++ has initialized 3 instanced objects just to make 1 Dog object?

没有。这意味着,派生 class 会隐式调用父 classes 析构函数,因此它们仍然有机会释放私有资源。在这种情况下,所有三个析构函数都被调用,因为只有一个 Dog class 实例被销毁。

the same seems to go for constructors as well

构造函数具有类似的概念,但与析构函数不同,您经常显式调用它们,所以这并不奇怪。

有一个用于 constructing objects, and the inverse sequence is used for destroying them 的特定序列。

施工用:

Initialization order

The order of member initializers in the list is irrelevant: the actual order of initialization is as follows:

  1. If the constructor is for the most-derived class, virtual bases are initialized in the order in which they appear in depth-first left-to-right traversal of the base class declarations (left-to-right refers to the appearance in base-specifier lists)
  2. Then, direct bases are initialized in left-to-right order as they appear in this class's base-specifier list
  3. Then, non-static data member are initialized in order of declaration in the class definition.
  4. Finally, the body of the constructor is executed

销毁:

Destruction sequence

For both user-defined or implicitly-defined destructors, after the body of the destructor is executed, the compiler calls the destructors for all non-static non-variant members of the class, in reverse order of declaration, then it calls the destructors of all direct non-virtual base classes in reverse order of construction (which in turn call the destructors of their members and their base classes, etc), and then, if this object is of most-derived class, it calls the destructors of all virtual bases.

Even when the destructor is called directly (e.g. obj.~Foo();), the return statement in ~Foo() does not return control to the caller immediately: it calls all those member and base destructors first.

本质上,构造首先构建基础 class 部分,然后构建派生 class,然后破坏以相反的顺序破坏它。

在您的代码中,首先执行 Dog 析构函数的主体,然后执行 Mammal 析构函数。首先执行它的主体,然后执行 Animal 基的析构函数。