2014-05-19 60 views
-6
#include <iostream> 
using namespace std; 
class Person 
{ 
public: 
     void P(){ cout << "Person P" << endl; } 
     virtual void Print(){ cout << "Person Print" << endl; } 
     Person(){ cout << "Constructor Person" << endl; } 
     virtual ~Person(){ cout << "Dectructor Person" << endl; } 
}; 
class Developer : public Person 
{ 
public: 
     void Pi() { cout << "Developer Pi" << endl; } 
     void Print() override 
     { 
       cout << "Developer Print" << endl; 
     } 
     Developer(){ cout << "Constructor Develoeper" << endl; } 
     ~Developer(){ cout << "Dectructor Develoer" << endl; } 
}; 
int main() 
{ 
     Person *p = new Person(); 
     Developer* d = dynamic_cast<Developer*>(p); 
     d->Pi(); 

     delete p; 
     delete d; 
    return 0; 
} 

输出:派生类的方法,无需构造

Constructor Person 
Developer Pi 
Dectructor Person 

为什么我可以调用Developer的功能Pi

如何在不使用Developer的构造函数的情况下调用Pi

请注意,Pi只在类别Developer中声明。

+0

你可以做任何你想做的事情,但会导致**未定义的行为** – Rakib

+0

请看这个非常全面的答案为什么这是UB:http://stackoverflow.com/a/2474021/3549027 – dlf

回答

3

你不行。你的代码有一个未定义的行为。如果我修改main()功能:

int main() 
{ 
    Person *p = new Person(); 
    Developer* d = dynamic_cast<Developer*>(p); 
    assert(d!=0); 
    d->Pi(); 

    delete p; 
    delete d; 
    return 0; 
} 

然后断言d!=0被触发。这表明dynamic_cast失败。您在空指针上调用Developer::Pi,并使用您的编译器,它运行正常,可能是因为Developer::Pi不使用this

+1

@irineau,这不是OP的答案。如果没有'assert'代码的工作,并且令人惊讶地调用'Pi',问题就是为什么 – Rakib

2

Developer* d = dynamic_cast<Developer*>(p);
您有d == nullptr

d->Pi(); 你调用未定义行为:

方法一般相当于是其采取额外this为参数,当你不使用this的方法似乎在你的情况下工作的功能。

0

这是因为dynamic_cast。您不是指实例中的任何变量,因此它不会失败。

访问任何虚拟方法或访问将存储在对象中的任何内容都会导致访问冲突。

0

通过声明d是一个指向Developer类的对象的指针,您可以向编译器提供提示。您还声明void Pi()不是虚拟的,因此编译器使用了早期绑定(编译时)。这意味着被调用函数的地址在编译过程中被锁定,并且不需要对象进行评估(与虚拟方法不同)

当调用d-> Pi()时,它与您的相同'用Pi调用Pi(d)指向Developer实例的指针。在MFC中有一种方法称为验证或类似的东西,它使用相同的机制来检查你的指针是否为空:)

你不会碰到删除d,因为它是在标准的,删除一个空指针是OK,并且什么也不做(删除一个脏指针是不确定的)。

只需将虚拟字添加到Pi方法签名中,或者向Developer类中添加一个字段并尝试在Pi方法中对该字段进行修改。你会看到不同之处;)