【问题标题】:Is the constructor of a derived class called when we new it using a base pointer是在我们使用基指针新建派生类时调用的构造函数
【发布时间】:2012-06-24 06:56:53
【问题描述】:
Class Shape {
    virtual Shape() = 0;
    virtual ~Shape() = 0;
}

Class Circle : Public Shape {
    Circle();
    ~Circle();
    // Something ...
}

int main () {
Shape* s = new Circle();
delete s;
}

是不是在调用Circle的构造函数?即使它是Shape的构造的不同名称? 删除s的时候,是不是调用Circle的析构函数?

【问题讨论】:

  • 这是 C# 吗?如果是这样,您可能希望将其添加为标签。
  • 这应该是 C++ 吗?如果是这样,将构造函数标记为虚拟是不合法的。

标签: c++ inheritance constructor destructor


【解决方案1】:

在 c++ 中,构造函数不能是虚拟的。

您提供的代码不是有效的 c++。

这里是更正后的代码,你可以在这里看到它运行:http://codepad.org/2fDc4S3e 程序的输出应该回答你所有的问题。我建议您使用代码来回答您可能遇到的任何其他问题。

class Shape {
public:
    virtual ~Shape() = 0;
};

Shape::~Shape() { std::cout << "Shape dtor called" << std::endl;} // Since you declared the destructor pure virtual you must define it

class Circle : public Shape {
public:
    Circle() { std::cout << "Circle ctor called." << std::endl; }
    ~Circle() { std::cout << "Circle dtor called." << std::endl; }
    // Something ...
};

int main () 
{
  Shape* s = new Circle(); // This will call the constructor of Circle
  delete s; // This will call the destructor of Circle and then the dtor Shape.
  return 0;
}

【讨论】:

    【解决方案2】:

    是的,Circle 的 dtor 将被调用:

    • 因为 Shape 的 dtor 是虚拟的,所以从它继承的任何类都将具有虚拟 dtor。
    • 这意味着 dtor 不是直接调用的,而是通过 v-table 调用的:当您“删除 s”时,它调用 s.dtor() 调用 v-table 中的正确项目,即 Circle 的 dtor。李>

    【讨论】:

      【解决方案3】:

      构造函数不能是虚拟的。

      class Shape {
          virtual ~Shape() = 0;
      };
      
      class Circle : public Shape {
          Circle() {};
          ~Circle() {};
      };
      
      int main() {
          Shape *s = new Circle();
          delete s;
      }
      

      是的,new Circle() 调用了 Circle 的构造函数。这是因为表达式new &lt;type&gt;&lt;optional initializer&gt; 分配了足够的内存,然后通过调用适当的构造函数(或非类类型的其他初始化)对其进行初始化。这一点不需要是虚拟的,因为您已经明确声明了最派生的类型。

      new Circle() 的结果是一个指向 Circle 的指针。将此类型分配给指向 Shape 类型指针的变量涉及隐式转换。转换的结果是指向 Circle 的基本 Shape 子对象的指针。同样,这一切都不是虚拟的,因为 Shape 不是虚拟基础,它只是一个常规基础对象,并且它在 Circle 内的位置是静态已知的。

      delete s 确实调用了 Circle 析构函数。这确实使用了虚拟调度。编译器知道它正在删除一个 Shape,并且 Shape 的析构函数是虚拟的,因此它查找适当的析构函数,即~Circle(),并调用它。如果 Shape 的析构函数不是虚拟的(并且实际上在某处有定义),则不会这样做,只有 Shape 对象会被破坏,而不是 Circle 对象,并且释放可能无法正确完成。行为将是未定义的。

      【讨论】:

        猜你喜欢
        • 2016-07-19
        • 2018-07-21
        • 2021-09-09
        • 2018-07-16
        • 1970-01-01
        • 1970-01-01
        • 2015-08-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多