分享
三行代码  ›  专栏  ›  技术社区  ›  Videl Ichinose

如何不删除基类对象的副本? - How to not delete a copy of base class object?

c++
  •  1
  • Videl Ichinose  · 技术社区  · 1 周前

    我的问题是,当我使用继承类时,基类会删除2次(继承的副本也是如此)。有机会不复制基类吗?还是不删除?

    #include <iostream>
    
    using namespace std;
    class base {
    public:
        base() { cout << "*B"; }
        ~base() { cout << "~B"; }
    };
    
    class restaurant : virtual public base {};
    
    int main() {
        base* d1 = new base;
        restaurant restaurant;
        delete d1;
        return 0;
    }
    

    输出是 *B*B~B~B 但我想 *B*B~B 因为我没有删除餐厅,只删除基本对象。

    4 回复  |  直到 1 周前
        1
  •  3
  •   Thomas    1 周前

    你不是 delete 惯性导航与制导 restaurant ,但你没有 new 它也可以;它是在自动存储(“堆栈”)中分配的,而不是动态存储(“堆”)。自动存储中的对象在超出范围时调用其析构函数。这就是为什么 餐厅 在这种情况下,析构函数仍然被调用。

    如果你写了:

    restaurant *restaurant = new restaurant;
    

    你会看到你期待的行为。当然,打电话 新的 没有匹配的 删除 您将泄漏对象,因此不建议这样做。

        2
  •  2
  •   Guillaume Racicot    1 周前

    首先,在作用域的末尾自动删除具有自动存储的对象。如此声明 restaurant restaurant; 将构造一个餐厅,但也将在 main 功能。

    试试这个:

    struct A {
        A() { std::cout << "A()"; }
        ~A() { std::cout << "~A()"; }
    };
    
    struct B : A {
        B() { std::cout << "B()"; }
        ~B() { std::cout << "~B()"; }
    };
    
    auto main() -> int {
        B b;
    } // b destroyed here
    

    The output is :

    A()B()~B()~A()
    

    它的行为就像一堆。首先构造基类,然后构造派生类。然后,它首先销毁派生类,最后销毁基类。

    对于大多数C++习语来说,这种行为是非常重要的。

    考虑一下:

    struct A {
        A() : arr(new int[3]{1, 2, 3}) {}
        ~A() { delete[] arr; }
        int* arr = nullptr;
    };
    
    struct B : A {
        B() {}
        ~B() {}
        auto stuff() -> int {
            return std::accumulate(arr, arr + 3, 0);
        }
    };
    
    auto main() -> int {
        B b;
        return b.stuff(); // returns 1 + 2 + 3
    }
    

    如果构造函数 A() 不是先被处决的?数组将为空。那就糟了。

    也。。。如果毁灭者 ~A() 没有被处决?那将是一个 内存泄漏 . 那太糟糕了。

    构造函数和析构函数具有保证的执行和定义良好的顺序。所以你不用打电话 super() ~super() 在所有的构造函数和析构函数中。因为你会忘记叫它。析构函数和构造器不是你想忘记调用的东西,否则在c中使用自由函数没有任何优势。

        3
  •  0
  •   Guillaume Racicot    1 周前

    输出是预期输出。 我在你的主函数代码中添加了注释。

    int main() {
    
        //Create base class object and constructor will be called
        //This object is allocated on heap
        base* d1 = new base;
    
        //Create derived class object
        //first constructor of base and then derived (if defined) will be called 
        //This object is allocated on stack
        restaurant restaurant;
    
        //Free memory and Call destructor of base class object
        delete d1;
    
        return 0;
    
        //After bracket, stack object will go out of scope and destructor will be called.
        //First derived (if defined) class destructor and then base class destructor.
    }
    

    要获得预期输出: *B*B~B

    restaurant *restaurant = new restaurant;
    

    但如果你不删除它,它会在你的程序中造成内存泄漏。