首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >c++继承问题

c++继承问题
EN

Stack Overflow用户
提问于 2011-02-05 18:21:31
回答 3查看 165关注 0票数 0

我对此有一个问题:

代码语言:javascript
复制
class A
{
  int a;
  int* pa;
public:
   A(int i):a(i) , pa(new int(a))
   {
      cout<<"A ctor"<<a<<endl;
   }
   ~A()
    {
      delete pa;
      cout<<"dtor\n";
    }
    int * &get()
    {
     return pa;
    }
};

class B : public A
{
     int b;
public:
      B (A obj): A(obj) , b(0)
      {
       cout<<"B ctor\n";
      }
      ~B()
      {
       cout<<"B dtor\n";
      }
};

int main()
{
 int i = 23 ; 
 A* p = new B(i);
}

能告诉我为什么要编译main中的最后一行吗?我把一个int传递给B的构造函数,它需要一个A对象,我相信在B的构造函数中int会被转换成A,但为什么呢?

提前谢谢。

艾芙莉。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-02-05 18:24:49

由于您尚未将A构造函数声明为explicit,因此编译器将使用i创建一个异常的A实例,并使用它来初始化B实例。如果您不希望编译器执行这些隐式转换,请将您的构造器声明为explicit。然后你会得到一个编译器错误。

票数 5
EN

Stack Overflow用户

发布于 2011-02-05 18:32:26

因为A有一个接受int的单参数构造函数,并且没有被标记为explicit,所以您可以隐式地将int转换为A

执行new B(i)时,因为B唯一可行的构造函数接受A,所以会尝试将i转换为A并从中构造新的B。这种转换是通过使用接受int的构造函数创建一个临时A来完成的。

当构造B对象时,基类A是从临时A复制构造的,这意味着从临时A复制成员变量apa

严格地说,因为构造函数通过值接受A对象,所以从概念上讲,将再次复制临时对象。然而,编译器可以通过直接从i构造B的构造函数参数来消除临时,因此效果看起来很可能只是一个副本。

这将导致严重错误,因为当临时A被销毁时,delete pa将导致动态分配的int被销毁,但新分配的B对象的基类A仍将具有该指针的副本,该副本现在不再指向无效对象。如果编译器没有消除其中一个副本,“双重释放”将立即发生。

A的关键方面是它有一个用户定义的析构函数,用于执行资源操作(释放)。这是一个强烈的警告,因为编译器生成的版本可能与A的设计不一致,所以A需要用户定义的复制构造函数和复制赋值运算符。

这就是所谓的“三个规则”,即如果你需要解构函数、复制构造函数或复制赋值操作符中的一个的用户定义版本,那么你很可能需要所有这些函数的用户定义版本。

如果您试图在示例中释放动态分配的B对象,则很可能会导致“双重释放”错误。此外,A的析构函数需要标记为virtual,以便通过指向A的指针进行删除才能正常工作。

票数 2
EN

Stack Overflow用户

发布于 2011-02-05 18:27:13

由于存在从intA的转换,因此您的代码将被隐式地转换为

代码语言:javascript
复制
 A* p = new B(A(i));
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4906301

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档