【问题标题】:Derived class's method without constructor [duplicate]没有构造函数的派生类方法[重复]
【发布时间】:2014-07-07 14:43:16
【问题描述】:
#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 类中声明。

【问题讨论】:

标签: c++ inheritance


【解决方案1】:

你不能。您的代码具有未定义的行为。如果我将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

【讨论】:

  • @irineau,这不是 OP 的答案。没有assert,代码可以正常工作并且令人惊讶地调用Pi,问题是为什么
【解决方案2】:

Developer* d = dynamic_cast&lt;Developer*&gt;(p);
你有d == nullptr

d-&gt;Pi(); 您调用未定义的行为:

方法通常等效到一个函数,该函数将额外的this 作为参数,并且由于您不使用this,因此该方法似乎适用于您的情况。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

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

      您不会在 delete d 上崩溃,因为它在标准中,删除空指针是可以的,并且什么都不做(删除脏指针是未定义的艰难)。

      只需将单词 virtual 添加到 Pi 方法签名或添加一个字段到 Developer 类并尝试修改 Pi 方法中的该字段。然后你会看到区别;)

      【讨论】:

        猜你喜欢
        • 2020-09-22
        • 2021-07-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多