泫溯 2024-06-15 15:32 采纳率: 94.7%
浏览 3
已结题

关于#c++#的问题:请问这个多态代码,在VS上为什么每个类加一个构造或析构函数

img

img


请问这个多态代码,在VS上为什么每个类加一个构造或析构函数,就没法正常运行了呢?
而且那样之后还必须在Derivated类对象后加(),而且运行出错?
如果改成base2后会出现Derivated类构造析构函数都不调用的情况。
dl求解决

  • 写回答

3条回答 默认 最新

  • 专家-赤兔[在线] 优质创作者: 编程框架技术领域 2024-06-15 15:32
    关注

    引自免费微信小程序:皆我百晓生

    在C++中,当涉及到继承和多态时,构造函数和析构函数的管理变得尤为重要。你的描述中提到,当你给每个类添加构造函数或析构函数时,代码在Visual Studio上不能正常运行,这通常是因为构造和析构的调用顺序以及资源管理不当所导致的。

    构造函数和析构函数的作用

    • 构造函数:用于初始化对象的成员变量,确保对象处于一个有效状态。
    • 析构函数:用于释放对象占用的资源,例如动态分配的内存。

    问题分析与解决方案

    1. 析构函数的虚化

    当一个类作为基类时,如果它包含动态分配的资源(如new),那么应该将析构函数声明为虚的。这样可以确保在删除派生类对象时,会先调用派生类的析构函数,然后是基类的析构函数,从而正确地释放所有资源。

    class Basel {
    public:
        virtual ~Basel() {} // 声明虚析构函数
        virtual void display() const;
    };
    
    class Base2 : public Basel {
    public:
        virtual ~Base2() {} // 派生类也应该声明虚析构函数
        void display() const override;
    };
    
    class Derived : public Base2 {
    public:
        virtual ~Derived() {} // 同样,Derived类也需要虚析构函数
        void display() const override;
    };
    

    2. 构造函数的调用

    在派生类中,如果没有显式调用基类的构造函数,编译器会默认调用基类的无参构造函数。如果基类的构造函数是私有的或有参数的,你需要在派生类的构造函数中明确调用基类的构造函数。

    class Basel {
    public:
        Basel() { /* 初始化代码 */ }
        virtual ~Basel() {}
        virtual void display() const;
    };
    
    class Base2 : public Basel {
    public:
        Base2() : Basel() {} // 明确调用基类构造函数
        virtual ~Base2() {}
        void display() const override;
    };
    
    class Derived : public Base2 {
    public:
        Derived() : Base2() {} // 明确调用基类构造函数
        virtual ~Derived() {}
        void display() const override;
    };
    

    3. 对象创建与销毁

    在你的代码中,直接声明对象(如Base1 base1;)时,构造函数会被自动调用。但是,如果你试图调用一个构造函数而没有提供必要的参数(如果构造函数需要参数的话),或者尝试调用析构函数(这是不允许的),你可能会遇到编译错误或运行时错误。

    示例代码

    下面是一个修改后的示例,包括了虚析构函数和正确的构造函数调用:

    #include <iostream>
    
    class Basel {
    public:
        Basel() { std::cout << "Basel constructor called\n"; }
        virtual ~Basel() { std::cout << "Basel destructor called\n"; }
        virtual void display() const { std::cout << "Basel::display()\n"; }
    };
    
    class Base2 : public Basel {
    public:
        Base2() : Basel() { std::cout << "Base2 constructor called\n"; }
        virtual ~Base2() { std::cout << "Base2 destructor called\n"; }
        void display() const override { std::cout << "Base2::display()\n"; }
    };
    
    class Derived : public Base2 {
    public:
        Derived() : Base2() { std::cout << "Derived constructor called\n"; }
        virtual ~Derived() { std::cout << "Derived destructor called\n"; }
        void display() const override { std::cout << "Derived::display()\n"; }
    };
    
    void fun(Basel *ptr) {
        ptr->display();
    }
    
    int main() {
        Basel base1;
        Base2 base2;
        Derived derived;
    
        fun(&base1);
        fun(&base2);
        fun(&derived);
    
        return 0;
    }
    

    这段代码将正确地显示每个类的构造和析构顺序,并展示多态的display()函数调用。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(2条)

报告相同问题?

问题事件

  • 系统已结题 6月27日
  • 已采纳回答 6月19日
  • 创建了问题 6月15日