C++ 多态性。为啥这行得通?
Posted
技术标签:
【中文标题】C++ 多态性。为啥这行得通?【英文标题】:C++ Polymorphism. Why is this working?C++ 多态性。为什么这行得通? 【发布时间】:2014-11-21 05:19:50 【问题描述】:这不应该是不正确的吗? :
A* apb = (A*)&b; //a pointer to b
我预计会出现错误,或者至少是警告。
为什么这在 Visual C++ 2013 (v120) 或 g++ (gcc 4.8.2) 中没有给我任何警告?
#ifndef A_H
#define A_H
#include <stdio.h>
class A
public:
A()
virtual ~A()
void print() printf("printA\n");
virtual void printVirtual() printf("printVirtualA\n");
;
#endif // A_H
#ifndef B_H
#define B_H
#include "A.hpp"
class B : A
public:
B()
void print() printf("printB\n");
virtual void printVirtual() printf("printVirtualB\n");
;
#endif //B_H
int main()
A a;
B b;
A* apb = (A*)&b; //a pointer to b
B* bpa = (B*)&a; //b pointer to a
apb->print(); // printA
apb->printVirtual(); // printVirtualB
bpa->print(); // printB
bpa->printVirtual(); // printVirtualA
return 0;
输出:
printA
printVirtualB
printB
printVirtualA
我怀疑这是因为我的类在内存中对齐,所以有一个有效的 Vtable。
这是一个“隐式”dynamic_cast 吗?
据我所知,这样做不应该是正确的。
【问题讨论】:
您正在强制编译器使用 C 风格的转换进行转换,所以它不会抱怨。哎呀,你可以做float* bad = (float*)&b;
,编译器仍然不会抱怨。但这并不能使它有效。我相信你的演员都不合法(B
私下继承自 A
,而 A
不是从 B
派生的)。
向下转型呢? B* bpa = (B*)&a; //b pointer to a
是不是因为类有相同的结构才能正确执行?
这实际上是未定义的行为并且是非法的。但是,它似乎可以工作,因为A
和B
是非常简单的类(它们没有成员,并且这些函数只是打印文本而不做任何复杂的事情)。由于A
和B
非常简单并且非常接近相同,因此它们可以充当彼此的替代品。这有点像用凳子的腿代替桌腿:它们不一样,但足够接近它可能会起作用。但是,尝试用凳子的腿代替大象腿,事情不会那么顺利......
@Cornstalks 谢谢,这正是我正在寻找的答案。我仍然想知道为什么根本没有警告。
【参考方案1】:
这正是 vtables 的用途。非虚函数被称为匹配容器的类型,虚函数被称为匹配被指向对象的类型。
A* apb = (A*) &b;
.... 是完美的代码,是虚拟多态的经典例子。
【讨论】:
然而,B* bpa = (B*)&a;
不是完美的代码...(另外:这些函数都不是静态的)。另外,私有继承不会破坏这段代码的合法性吗?
确实如此。我将非虚拟函数称为静态,因为它以静态方式调用,而不是按照 c++ 关键字。但你是对的。
这有点像,但不完全如此。该函数使用this
指针调用(只是碰巧没有使用它),这意味着它的调用约定与static
函数不太一样。
静态我的意思是调用地址不是在运行时确定的,而是在编译时确定的,而不是在运行时使用 vtable 虚拟/动态地确定【参考方案2】:
A* apb = (A*)&b;
从派生类初始化基类指针是完全可以的(假设b
是B
类型,如您所示)。你甚至不需要强制转换操作
A* apb = &b;
void print()
成员函数没有标记为virtual
,因此成员函数是在您手头的实际实例上调用的。
【讨论】:
我不认为这完全没问题。请注意,他是私人继承,而不是公开继承。 @Cornstalks 好地方。是的,强制转换可能会隐藏为A* apb = &b;
给出的错误。虽然公开继承应该可以解决这个问题,但行为并没有真正的改变。关键是,print()
函数不是 virtual
。【参考方案3】:
A* apb = (A*) &b;
这完全没问题。指向派生对象的基指针。这种方案主要是通过抽象类(或接口)来实现多态性
【讨论】:
以上是关于C++ 多态性。为啥这行得通?的主要内容,如果未能解决你的问题,请参考以下文章
为啥以及何时使用多态性将基类指向 C++ 中的派生类 [重复]
c++中只有使用指针才能多态吗?普通实例和引用为啥不能多态?