在派生类中声明虚函数(Virtual function declared in a derived

2019-09-18 07:31发布

在这里,我已经宣布在派生类另一个虚拟功能。

#include <iostream>

using namespace std;

class A{
    string s;
    public:
    A(const string& name) : s(name){}
     virtual void f1(){cout << "f1 of base class" << endl;};
};

class B : public A{
    string p;
    public:
    B(const string& name) : A(name){}
    virtual void f2(){cout << "virtual function of derived class" << endl;}
    void f1(){cout << "f1 of derived class";}
};

int main() {
    A* arr[] = {new A("John"),new B("Bob")};
    arr[0]->f1();
    arr[1]->f1();
    arr[1]->f2();
    return 0;
}

函数调用ARR [1] - > F2()给出了错误“‘A类’没有名为‘F2’构件 ” .I很奇怪,为什么_vptr指向基类的VTABLE即使当B被upcasted到A.

此外,我想知道,是内联虚函数安全吗?

Answer 1:

因为不存在这样的构件。 virtual函数采取从那里他们被宣布通过所有派生类先顺着类。 他们没有得到冒泡。 当编译器着眼于arr[ i ]->f2()它看起来向上的定义arr其类型。 arr具有(静态)类型A 。 因此,编译器查找A的定义为一个合适的定义f2 ,并且没有发现任何。 因此,诊断。

virtual功能可以安全地内联。 事实上,所有在类定义编译器隐式内联。 所以,你的A::f1已经被内联。



Answer 2:

你试图调用f2()上的A* ,和A没有f2()声明。

virtual的方法,当通过一个指向基类(包括类对象本身)呼吁,在运行时解决手段的基础上,你调用它的对象的vptr表。 它不会使该方法在基类中可见。

内联虚函数是非常安全的,但你不一定会得到你期待它的性能提升。 内联意味着该函数的代码是由编译器在调用点复制粘贴。 查看内联的C ++超级FAQ以及为什么它在天空中的馅饼

内联是一个编译时间的概念。 虚拟方法调用,叫上一个指向基类,在运行时解决。

即下面调用一个函数是虚拟的,可内联:

B myB("The B.");
b.f1(); // not virtual, might be inlined


Answer 3:

先易:

此外,我想知道,是内联虚函数安全吗?

是的,虚函数可以被内联,但多态性保证始终工作。

例如:

B b;
b.f2();

可以在编译时加以解决,而不使用虚拟表,因为编译器知道对象的类型是B

我很奇怪,为什么_vptr指向基类的VTABLE即使改编[1] upcasted至B.

事实并非如此。 它指向类的虚表B ,但是编译器并不这么看。 虚表是一个实现细节。 你调用上的一个函数A* ,所以B的方法是不可见的。 在这个简单的例子,它很容易,但怎么可能,一般来说,编译器告诉arr[1]是一个指向B的事实呢? 这是多态的整点,你抽象掉派生类型。

你可以做的是:

dynamic_cast<B*>(arr[1]) ? (dynamic_cast<B*>(arr[1]))->f2() : (void)0;


Answer 4:

想想看,这种方式。 在编译时,编译是完全忘记的实际类型,所述对象的arr[i]是指向。 这种类型的才成为在运行时知道。 所以,当你写的东西是这样的:

arr[i]->f2();

编译器不知道生产什么代码,以使该呼叫发生。 什么是F2? 难道在B声明的F2? 如果你也有一个名为C AA的子类,其中也有一个名为F2虚函数,而常用3 [I]点恰好是C类的对象? 我们不知道。

你会马上看到,在这种情况下,唯一理智的行为是产生一个错误。



Answer 5:

arr[1]的类型为A*不具有一个称为方法f2 。 你不得不投arr[1]B* ,但我不认为这是一个好主意。 更改你的数据结构来代替。



文章来源: Virtual function declared in a derived class