指向派生 class 的指针是否首先创建基 class?
Does pointer to derived class create the Base class first or not?
我有以下代码
#include <iostream>
using namespace std;
class B{
int i;
public:
B(){
cout << "Constructing B\n";
}
void print(){
cout << "Printing from B with size : "<<sizeof(*this)<<endl;
}
};
class D:public B{
int i;
public:
D(){
cout << "Constructing D\n";
}
void print(){
cout << "Printing from D with size : "<<sizeof(*this)<<endl;
}
};
int main(){
B b;
b.print();
D d;
d.print();
D* dp;
dp->print();
}
这给了我以下输出:
Constructing B
Printing from B with size : 4
Constructing B
Constructing D
Printing from D with size : 8
Printing from D with size : 8
那么,当您创建指向派生 class 的指针时,它并没有首先创建基 class 的实例,这是真的吗?我不认为这是真的,因为 D class 的大小就是证据。但它甚至没有调用基础 class 构造函数。谁能解释一下?
指针不创建任何东西。指针只是指针——包含地址的标量对象。您有责任使您的指针指向内存中的正确位置。
在您的示例中,指针 dp
未初始化。你从来没有让它指向任何地方,所以它没有指向任何地方。您尝试调用 dp->print()
会产生未定义的行为。故事结束。
现在你的指针根本没有被初始化,所以尝试使用它会产生未定义的行为。尝试类似的东西:
D *dp = new D;
dp->print();
delete dp;
或者为了做得更好,比如:
std::unique_ptr<D> dp = std::make_unique<D>();
dp->print();
...并且 unique_ptr
将在超出范围时自动删除 D
。
但是请注意,您已将 print
定义为非虚函数,因此调用的函数将取决于所使用的指针(或引用)类型,不是它引用的对象的类型。另外,你还没有定义虚拟dtor。
因此,如果您要执行以下操作:
B *p = std::make_unique<D>();
p->print(); // would invoke B::print, even though the object is a D
...当它超出范围时,它会被错误地销毁,所以你会得到未定义的行为。要更正此问题,您需要将 B 更改为如下内容:
class B{
int i;
public:
B(){
cout << "Constructing B\n";
}
virtual void print(){
cout << "Printing from B with size : "<<sizeof(*this)<<endl;
}
virtual ~B() = default;
};
当您执行此操作时,答案是 "yes"--当您创建派生对象时,它将首先调用基础 class 的构造函数,然后调用派生对象 class。当派生对象被销毁时,情况正好相反:首先调用派生 class 的 dtor,然后当它完成时,将执行基 class 的 dtor。
您可以使用强大的 多态性 将 Base
的指针分配给 Derived
对象。这是可能的,因为 Derived
实现了 Base
包含的所有内容。因此,隐含的是 Derived
底层在它自己的实例化过程中实例化了 Base
。
class Base
{
public:
Base()
{}
}
class Derived : public Base
{
public:
Derived()
{}
}
Derived *derived = new Derived();
Base *base = derived;
在派生class之前构造基class。您的输出反映了这一点。看看这个
//Constructs Base class
Constructing B
//Constructs Derived class
Constructing D
//Prints from derived
Printing from D with size : 8
您的代码在不调用构造函数的情况下打印两次 Printing from D with size : 8
的原因是您的代码从未创建 D
.
的第二个实例
D* d;
^^^^ Declares a pointer to a D, Does not create a D!
当您调用 d->print();
时,它是未定义的行为,因为 d
没有指向 D
的实例。最后,您的代码会打印一个在编译时确定的值(sizeof(D)
是一个编译时值)并且不会触及您的代码运行时的 this
指针。
请参阅 sizeof
here 的文档。
我有以下代码
#include <iostream>
using namespace std;
class B{
int i;
public:
B(){
cout << "Constructing B\n";
}
void print(){
cout << "Printing from B with size : "<<sizeof(*this)<<endl;
}
};
class D:public B{
int i;
public:
D(){
cout << "Constructing D\n";
}
void print(){
cout << "Printing from D with size : "<<sizeof(*this)<<endl;
}
};
int main(){
B b;
b.print();
D d;
d.print();
D* dp;
dp->print();
}
这给了我以下输出:
Constructing B
Printing from B with size : 4
Constructing B
Constructing D
Printing from D with size : 8
Printing from D with size : 8
那么,当您创建指向派生 class 的指针时,它并没有首先创建基 class 的实例,这是真的吗?我不认为这是真的,因为 D class 的大小就是证据。但它甚至没有调用基础 class 构造函数。谁能解释一下?
指针不创建任何东西。指针只是指针——包含地址的标量对象。您有责任使您的指针指向内存中的正确位置。
在您的示例中,指针 dp
未初始化。你从来没有让它指向任何地方,所以它没有指向任何地方。您尝试调用 dp->print()
会产生未定义的行为。故事结束。
现在你的指针根本没有被初始化,所以尝试使用它会产生未定义的行为。尝试类似的东西:
D *dp = new D;
dp->print();
delete dp;
或者为了做得更好,比如:
std::unique_ptr<D> dp = std::make_unique<D>();
dp->print();
...并且 unique_ptr
将在超出范围时自动删除 D
。
但是请注意,您已将 print
定义为非虚函数,因此调用的函数将取决于所使用的指针(或引用)类型,不是它引用的对象的类型。另外,你还没有定义虚拟dtor。
因此,如果您要执行以下操作:
B *p = std::make_unique<D>();
p->print(); // would invoke B::print, even though the object is a D
...当它超出范围时,它会被错误地销毁,所以你会得到未定义的行为。要更正此问题,您需要将 B 更改为如下内容:
class B{
int i;
public:
B(){
cout << "Constructing B\n";
}
virtual void print(){
cout << "Printing from B with size : "<<sizeof(*this)<<endl;
}
virtual ~B() = default;
};
当您执行此操作时,答案是 "yes"--当您创建派生对象时,它将首先调用基础 class 的构造函数,然后调用派生对象 class。当派生对象被销毁时,情况正好相反:首先调用派生 class 的 dtor,然后当它完成时,将执行基 class 的 dtor。
您可以使用强大的 多态性 将 Base
的指针分配给 Derived
对象。这是可能的,因为 Derived
实现了 Base
包含的所有内容。因此,隐含的是 Derived
底层在它自己的实例化过程中实例化了 Base
。
class Base
{
public:
Base()
{}
}
class Derived : public Base
{
public:
Derived()
{}
}
Derived *derived = new Derived();
Base *base = derived;
在派生class之前构造基class。您的输出反映了这一点。看看这个
//Constructs Base class
Constructing B
//Constructs Derived class
Constructing D
//Prints from derived
Printing from D with size : 8
您的代码在不调用构造函数的情况下打印两次 Printing from D with size : 8
的原因是您的代码从未创建 D
.
D* d;
^^^^ Declares a pointer to a D, Does not create a D!
当您调用 d->print();
时,它是未定义的行为,因为 d
没有指向 D
的实例。最后,您的代码会打印一个在编译时确定的值(sizeof(D)
是一个编译时值)并且不会触及您的代码运行时的 this
指针。
请参阅 sizeof
here 的文档。