重写非虚拟方法
Overriding Non-Virtual methods?
下面是一些代码,旨在显示何时覆盖虚拟方法。它输出:BB一个一个B一个这是对的吗?我以为酒吧方法不能被覆盖...?
#include <iostream>
using namespace std;
class A
{
public:
virtual void foo(){cout<<"A"<<endl;}
void bar(){cout<<"A"<<endl;}
};
class B : public A
{
public:
void foo(){cout<<"B"<<endl;}
void bar(){cout<<"B"<<endl;}
};
int main()
{
B b;
A * pA = new A;
A * pA2 = &b;
b.foo(); b.bar();
pA->foo(); pA->bar();
pA2->foo(); pA2->bar();
}
我没有看到任何错误:
B b;
b.foo(); b.bar();
声明并初始化B
的实例,编译类型为B
,运行时类型为B
。不需要多态性(也无法实现,因为不涉及指针(。
A * pA = new A;
pA->foo(); pA->bar();
声明指向A
的指针,并使用 A
的实例对其进行初始化。即使在这种情况下不需要多态性也有效,因此调用A
的foo()
和bar()
。
A * pA2 = &b;
pA2->foo(); pA2->bar();
声明指向A
的指针,并使用对 B
的引用对其进行初始化。编译时类型为A*
,运行时类型为B*
。通过虚函数应用多态性,因此B::foo()
虚方法,而非虚拟方法A::bar()
b.foo()
给出B
,
b.bar()
还给出了隐藏A::bar()
的B
。它不是覆盖,而是名称隐藏。
pA->foo()
给出A
,pA->bar()
给出A
,
pA2->foo()
给出了B
,因为它是一个虚拟函数。
pA2->bar()
给出了A
,因为它不是虚拟函数。它是静态链接的,它调用A::bar()
。
前两个输出都应该是 B,因为您要在 B 类型的对象上调用 foo(( 和 bar((。由于你没有使用指针,编译器知道它是 B 类型的对象,因此不需要查阅 vtable 来调用该方法,所以即使 bar(( 不是虚拟的,编译器也知道使用 B 实现。
接下来的两个输出都应该是 A,因为您要在指向 A 类型的对象的指针上调用 foo(( 和 bar((。在这种情况下,foo(( 是虚拟的,vtable 指向该方法的 A 实现。bar(( 不是虚拟的,因此编译器决定使用 A 实现。
最后两个输出应该是 B 和 A,因为您要在指向 B 类型的对象的指针上调用 foo(( 和 bar((。在这种情况下,foo(( 是虚拟的,vtable 指向该方法的 B 实现。bar(( 不是虚拟的,因此编译器决定使用 A 实现,因为您使用的是指向类型 A 对象的指针。
这是正确的,pA2->bar(( 调用没有被覆盖。 即使它是一个 B 对象,你也会将其强制转换为 A,编译器会为 A 类调用 A 成员函数。
foo(( 是虚拟的,因此包含在类 B 中的是一个指针,指向哪个版本的 foo(( 对于该类是正确的,无论它被强制转换为何处。
此包含称为指向虚函数表的指针。 一旦你的类有虚拟成员,就会为它创建一个静态函数表(并且还将包括任何其他后续虚函数(,此外还有一个常量隐藏成员指针指向此表。 当您强制转换对象时,函数表保持不变,任何虚拟函数都将保持"附加"到原始类型。
PS,别忘了删除pA...您当前有内存泄漏:)
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 跨 DLL 边界访问虚拟方法是否安全/可能?
- 是否可以使用基类非虚拟方法中的派生类虚拟方法?
- 如何编写 operator= 用于使用虚拟方法与非平凡成员的匿名联合
- 让编译器告诉什么确切的纯虚拟方法使结构抽象?
- 使用模板而不是虚拟方法的管道模式
- 派生类调用父类的方法,该方法调用重写的虚拟方法调用错误的方法
- 从纯虚拟类 (A) 派生的指针无法访问来自纯类 (B) 的重载方法
- 为什么调用没有正文的纯虚拟方法不会导致链接器错误?
- 出于什么目的,非虚拟方法将与C++一起使用?
- 为什么使用存储在虚拟方法表中的地址调用虚拟函数的函数会返回垃圾?
- 如何重写继承的嵌套类中存在的虚拟方法
- 私有虚拟方法有什么用?
- 派生类中纯虚拟基方法的专业化
- 基类可以声明虚拟方法但不定义它吗?仍然在派生类中定义
- googletest:测试基类具有纯虚拟方法的派生类时的核心转储
- 确保模拟的 GTest 方法覆盖虚拟方法
- 使用回调函数从构造函数调用虚拟/派生方法的替代方法?
- 如何调用孩子的方法:虚拟关键字不起作用