C++ 派生类';不带构造函数的s方法
为什么我可以调用C++ 派生类';不带构造函数的s方法,c++,inheritance,C++,Inheritance,为什么我可以调用Developer的函数Pi 没有开发人员的构造函数,如何调用Pi 请注意,Pi仅在类Developer中声明,您不能。您的代码具有未定义的行为。如果我将main()函数修改为: Constructor Person Developer Pi Dectructor Person intmain() { Person*p=新的Person(); 开发者*d=动态演员阵容(p); 断言(d!=0); d->Pi(); 删除p; 删除d; 返回0; } 然后断言d=0被触发。这表明
Developer
的函数Pi
没有开发人员的构造函数,如何调用Pi
请注意,Pi
仅在类Developer
中声明,您不能。您的代码具有未定义的行为。如果我将main()
函数修改为:
Constructor Person
Developer Pi
Dectructor Person
intmain()
{
Person*p=新的Person();
开发者*d=动态演员阵容(p);
断言(d!=0);
d->Pi();
删除p;
删除d;
返回0;
}
然后断言d=0
被触发。这表明dynamic_cast
失败。您在一个空指针上调用Developer::Pi
,并且使用您的编译器它恰好运行良好,这可能是因为Developer::Pi
没有使用这个和Developer*d=dynamic\u cast(p)代码>
您有d==nullptr
使用d->Pi()代码>
调用未定义的行为:
方法通常相当于将额外的此
作为参数的函数,并且由于您不使用此
此方法,因此该方法在您的情况下似乎有效。这是因为动态转换。您没有引用实例中的任何变量,因此它不会失败
访问任何虚拟方法或访问将存储在对象中的任何内容都会导致访问冲突。通过声明d是指向开发人员类对象的指针,可以向编译器提供提示。您还声明void Pi()不是虚拟的,因此编译器使用了早期绑定(编译时)。这意味着调用的函数的地址在编译过程中被固定,并且不需要计算对象(与虚拟方法不同)
调用d->Pi()时,与调用Pi(d)时相同,Pi使用指向开发人员实例的指针。在MFC中有一个名为Validate或类似的方法,它使用相同的机制检查指针是否为null:)
删除d不会导致崩溃,因为它在标准中,删除空指针是可以的,并且什么也不做(删除脏指针是未定义的)
只需将单词virtual添加到Pi方法签名中,或者将字段添加到Developer类中,并尝试在Pi方法中修改该字段。然后您将看到差异;) 你可以做任何你想做的事,但这会导致未定义的行为。请看下面这个非常彻底的答案,为什么这是UB:@irineau,这不是OP的答案。如果没有assert
,代码就会工作,并意外地调用Pi
,问题是为什么
Constructor Person
Developer Pi
Dectructor Person
int main()
{
Person *p = new Person();
Developer* d = dynamic_cast<Developer*>(p);
assert(d!=0);
d->Pi();
delete p;
delete d;
return 0;
}