【问题标题】:How to call virtual function of derived class through base class pointer如何通过基类指针调用派生类的虚函数
【发布时间】:2012-08-08 02:24:54
【问题描述】:

让我们看看这段代码:

class CBase
{
 public:
    virtual vfunc() { cout << "CBase::vfunc()" << endl; }
};

class CChild: public CBase
{
 public:
    vfunc() { cout << "CChild::vfunc()" << endl; }
};

int main() 
{
 CBase *pBase = new CBase;
 ((CChild*)pBase)->vfunc(); // !!! important 
 delete pBase;
 return 0;
}

输出是:

CBase::vfunc()

但我想看看:CChild::vfunc()

显式 ((CChild*)pBase) 强制转换为类型“CChild*”。那么为什么要调用派生的 vfunc() 我需要将“重要”字符串替换为: ((CChild*)pBase)->CChild::vfunc();

【问题讨论】:

    标签: c++ inheritance pointers virtual base


    【解决方案1】:

    这里的问题看起来很简单。 CBase 不能神奇地升级到 CChild!让我重写您的示例并添加一些 cmets。它应该是不言自明的......

    #include <iostream>
    
    class CBase {
    public:
        virtual void vfunc() { std::cout << "CBase::vfunc()" << std::endl; }
        virtual ~CBase(){} // Virtual destructor... extremely important! I'll let you figure out why as an excercise
    };
    
    class CChild: public CBase {
    public:
        void vfunc() { std::cout << "CChild::vfunc()" << std::endl; }
        ~CChild(){} // Is this destructor called? When? Try adding some std::cout to each destructor
    };
    
    int main() 
    {
        CBase *ptr1 = new CBase;
        CBase *ptr2 = new CChild;
    
        ptr1->vfunc(); // ptr1 points to an instance of CBase. This is what's important!!
        ptr2->vfunc(); // ptr2 points to an instance of CChild, which can be referenced to as a CBase
    
        delete ptr1;
        delete ptr2;
    }
    

    输出:

    CBase::vfunc()
    CChild::vfunc()
    

    PS:我刚刚意识到我迟到了大约 5 年,但既然我发现了这方面的教育价值,我还是会发布它!

    【讨论】:

      【解决方案2】:

      其他答案很重要-补充:如果您实际上可能正在处理CChild(例如,它是作为参数传递的引用),那么您可以使用dynamic_cast 向下转换。但是,对dynamic_cast 的高度依赖通常表明您的设计出了问题。

      演员详情可在此处找到: http://msdn.microsoft.com/en-us/library/cby9kycs(v=vs.80).aspx

      因此该过程需要通过dynamic_castCBase 参数转换为CChild,如果引用是CChild 并且dynamic_cast 成功,那么您可以确定您正在处理CChild然后您就可以安全地将其用作CChild

      【讨论】:

        【解决方案3】:

        你不能。 *pBaseCBase 类型的对象。您不能将其视为CChild,因为它不是CChild 对象。

        使用通过转换获得的指向CChild* 的指针会导致您的程序表现出未定义的行为。

        【讨论】:

        • 那么如何理解 Schildt H.:“基类指针也可以用作指向从该基类派生的任何类的对象的指针”。
        • 那么为什么字符串 ((CChild*)pBase)->CChild::vfunc() 有效?
        • @LEXX:首先,你应该烧掉那本书并获得a good introductory book。不过,他在那句话中所说的是正确的。基类指针 (CBase*) 可以指向派生自 CBase 的类型的对象(如 CChild)。但是,这不是您所做的:您的基类指针指向一个基类对象。例如,如果您有CBase* p = new CChild();,那么p 将是一个指向派生类对象的基类指针。
        • @LEXX:表达式不起作用。它似乎“工作”,但它也很容易导致您的程序崩溃,或导致您的计算机起火。您的程序表现出未定义的行为,这意味着它可以做任何事情。
        【解决方案4】:

        这不是它的工作原理 - 这是:

        CBase *pBase = new CChild;
        pBase->vfunc();
        

        virtual 函数调用在指针和引用上动态解析(除非你像你一样显式调用该方法)。这意味着无论你告诉编译器指针是什么,它都会在 vftable 中查找方法。在您的情况下,哪个是 vftableCBase

        【讨论】:

          猜你喜欢
          • 2016-10-06
          • 2010-12-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-21
          • 1970-01-01
          相关资源
          最近更新 更多