在这里,我已经宣布在派生类另一个虚拟功能。
#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.
此外,我想知道,是内联虚函数安全吗?
因为不存在这样的构件。 virtual
函数采取从那里他们被宣布通过所有派生类先顺着类。 他们没有得到冒泡。 当编译器着眼于arr[ i ]->f2()
它看起来向上的定义arr
其类型。 arr
具有(静态)类型A
。 因此,编译器查找A
的定义为一个合适的定义f2
,并且没有发现任何。 因此,诊断。
virtual
功能可以安全地内联。 事实上,所有在类定义编译器隐式内联。 所以,你的A::f1
已经被内联。
你试图调用f2()
上的A*
,和A
没有f2()
声明。
virtual
的方法,当通过一个指向基类(包括类对象本身)呼吁,在运行时解决手段的基础上,你调用它的对象的vptr表。 它不会使该方法在基类中可见。
内联虚函数是非常安全的,但你不一定会得到你期待它的性能提升。 内联意味着该函数的代码是由编译器在调用点复制粘贴。 查看内联的C ++超级FAQ以及为什么它在天空中的馅饼
内联是一个编译时间的概念。 虚拟方法调用,叫上一个指向基类,在运行时解决。
即下面调用一个函数是虚拟的,可内联:
B myB("The B.");
b.f1(); // not virtual, might be inlined
先易:
此外,我想知道,是内联虚函数安全吗?
是的,虚函数可以被内联,但多态性保证始终工作。
例如:
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;
想想看,这种方式。 在编译时,编译是完全忘记的实际类型,所述对象的arr[i]
是指向。 这种类型的才成为在运行时知道。 所以,当你写的东西是这样的:
arr[i]->f2();
编译器不知道生产什么代码,以使该呼叫发生。 什么是F2? 难道在B声明的F2? 如果你也有一个名为C AA的子类,其中也有一个名为F2虚函数,而常用3 [I]点恰好是C类的对象? 我们不知道。
你会马上看到,在这种情况下,唯一理智的行为是产生一个错误。
arr[1]
的类型为A*
不具有一个称为方法f2
。 你不得不投arr[1]
到B*
,但我不认为这是一个好主意。 更改你的数据结构来代替。