0

从我目前学到的知识来看,有两种多态性,编译时和运行时。在编译时,多态函数或运算符由编译器解析,而在运行时,它在运行时解析。编译时多态性的示例包括函数和运算符重载,运行时多态性包括函数覆盖和虚函数。此外,还有像早期绑定和晚期绑定这样的情况,我稍后会谈到。考虑以下代码:

class base {
public:
    void Print() {
        std::cout << "This is parent class\n";
    }
};

class derived : public base {
public:
    void Print() {
        std::cout << "This is derived class\n";
    }
};

如果我这样做:

base b1;
b1.Print();
derived d1;
d1.Print();

结果很明显:

This is parent class
This is derived class

当我使用指向基类的指针来操作这些函数时,真正的问题就开始了。

base b1;
derived d1;
base* pb = &b1;
base* pb2 = &d1;
pb->Print();
pb2->Print();

输出将是:

This is parent class
This is parent class

这是由于早期绑定,编译器检查调用函数的对象类型,而不是其处理的对象类型。很明显它是在编译时完成的。现在,如果我virtual在基类函数定义中使用关键字,那么我可以轻松地完成上述操作,这是由于后期绑定,它根据对象的类型为运行时保存了函数定义。这是运行时多态的一个例子。

抱歉花了太长时间,我的问题是,这是我们实现运行时多态性的唯一方法吗?此外,如果函数覆盖是运行时多态,那么前面的示例(即具有早期绑定的例子)也应该是运行时多态,因为它也在执行函数覆盖。

4

1 回答 1

0

没有什么会强迫您使用虚函数来实现运行时多态性。在性能关键代码中,经常会看到这样的事情,以避免虚函数调用的成本:

void foo(Base * _b)
{
   if(_b->typeID == TID_BASE)
   {
       b->bar();
   }
   else if(_b->typeID == TID_DERIVED)
   {
       static_cast<Derived*>(_b)->bar();
   }
}

其中类型 id 是某种形式的枚举或唯一标识类型的指针。也就是说,除非您实际测量到它对您的情况产生了性能差异,否则我绝不建议您这样做

关于你的最后一个问题。不,这绝不是后期绑定,因为您根本没有覆盖任何功能。在您的示例中,类中有一个Print函数,Base类中有一个函数Derived。通过将您的对象转换为Base,您明确地请求BasePrint函数。

于 2018-03-24T20:55:29.977 回答