c++继承问题
我对此有一个问题:
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
对象。我相信 int
在 B
的构造函数中被转换为 A
,但为什么呢?
提前致谢。
阿夫里。
I have a question about this:
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);
}
Can tell me why the last line in main
compiles? I pass an int
into B
's constructor which expects an A
object instead. I believe that the int
is translated to an A
in B
's constructor, but why?
Thanks in advance.
Avri.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
由于您尚未将
A
构造函数声明为explicit
,编译器正在使用i
创建A
的匿名实例并使用它初始化B
实例。如果您不希望编译器执行这些隐式转换,请将您的构造函数声明为显式
。然后你会得到一个编译器错误。Since you have not declared
A
constructor asexplicit
compiler is creating an anomymous instance ofA
usingi
and using it to initializeB
instance. If you don't want the compiler to do these implicit conversions declare your costructor asexplicit
. Then you will get a compiler error.由于
A
有一个采用int
且未标记为explicit
的单参数构造函数,因此您可以隐式转换int
> 到A
。当您执行
new B(i)
时,由于B
唯一可行的构造函数采用A
,因此会尝试转换i
到A
并从中构造新的B
。此转换是通过使用采用int
的构造函数创建临时A
来完成的。当构造
B
对象时,基类A
是从临时A
复制构造的,这意味着复制成员变量a< /code> 和来自临时
A
的pa
。严格来说,因为构造函数按值获取
A
对象,所以从概念上讲,临时对象被再次复制。然而,编译器可以通过直接从i
构造B
的构造函数参数来消除临时参数,因此效果很可能看起来只是一个副本。这会导致严重错误,因为当临时
A
被销毁时,delete pa
会导致动态分配的int
被销毁,但基类新分配的 B 对象的 A 仍将具有此指针的副本,该指针现在不再指向无效对象。如果编译器没有消除其中一个副本,则会立即发生“双重释放”。A
的关键方面是它有一个用户定义的析构函数来执行资源操作(释放)。这是一个强烈警告,表明A
需要用户定义的复制构造函数和复制赋值运算符,因为编译器生成的版本可能与A
的设计不一致。这被称为“三规则”,它表示如果您需要析构函数、复制构造函数或复制赋值运算符之一的用户定义版本,那么您可能需要所有这些的用户定义版本。
如果您尝试释放示例中动态分配的
B
对象,则可能会导致“双重释放”错误。此外,A
的析构函数需要标记为virtual
,以便通过指向A
的指针进行删除才能正常工作。Because
A
has a single parameter constructor which takes anint
and isn't markedexplicit
you can implicitly convert anint
to anA
.When you do
new B(i)
, because the only viable constructor forB
takes anA
, an attempt is made to converti
to anA
and construct the newB
from that. This conversion is done by creating a temporaryA
using the constructor that takes anint
.When the
B
object is constructed, the base classA
is copy constructed from the temporaryA
which means copying the member variablesa
andpa
from the temporaryA
.Strictly, because the constructor takes an
A
object by value, the temporary is, conceptually, copied again. The compiler may, however, eliminate the temporary by constructing the constructor parameter forB
directly fromi
so the effect may well look like just a single copy.This will cause a serious error because when the temporary
A
is destroyed,delete pa
will cause the dynamically allocatedint
to be destroyed but the base class A of the newly allocatedB
object will still have a copy of this pointer which now no longer points at an invalid object. If the compiler doesn't eliminate one of the copies, a "double free" will happen immediately.The key aspect of
A
is that it has a user-defined destructor that performs a resource action (deallocation). This is a strong warning thatA
needs a user-defined copy constructor and copy assignment operator because compiler generated version are likely not to work consistently with the design ofA
.This is known as the "rule of three" which says that if you need a user-defined version of one of the destructor, copy constructor or copy assignment operator then you are likely to need user-defined versions of all of them.
Were you to attempt to free the dynamically allocated
B
object in your example, it would likely cause a "double free" error. In addition,A
's destructor would need to be marked asvirtual
for a delete through a pointer toA
to work correctly.由于存在从
int
到A
的转换,因此您的代码会隐式转换为Since there is a conversion from
int
toA
, implicitly your code is translated into