是否可以通过单个指针访问多态类的不同祖先的虚拟方法?

Posted

技术标签:

【中文标题】是否可以通过单个指针访问多态类的不同祖先的虚拟方法?【英文标题】:Is it possible to access virtual methods of different ancestors of a polymorphic class through a single pointer? 【发布时间】:2015-09-23 13:40:40 【问题描述】:

我正在构建一个接口,使用单独的变量来访问单个接口会有点不方便,如果我能以某种方式创建两者的联合,那就太好了。

在文件中:

struct A
    virtual int auu()  return 41; 
;
struct B
    virtual int boo()  return 43; 
;

在另一个文件中:

#include <path to A, B>
struct C : public A, public B
    int auu()  return 20; 
    int boo()  return 22; 
;

还有另一个文件:

#include <declaration of A and B, but not C>

void doSth(A* a)

    B * b = dynamic_cast<B*>(a);
    /* I can only call auu with a */
    a->auu();
    /* I can only call boo with b */
    b->boo;

    /* Something like this would be ideal: */
    <??? type> * C_interface = dynamic_interface_cast<B*>(a)
    C_interface->auu();
    C_interface->boo();

那么是否可以只通过一个指针变量调用 auu 和 boo 而无需知道 C 的实现(而不是将其转换为 )?另外我想避免创建与 C 类无关的继承层次结构。

可能答案是否定的,但我很好奇这样的想法是否来自语言开发人员的想法,因为在我的原始头脑中,这不是一个牵强附会的想法。

编辑: 实际上,A 和 B 是抽象的。 A 是一个具有 size() 和 length() 等方法的 Simulation 对象。 B 是一个 IO 接口,实现 getter 和 setter,但它不知道大小,所以我必须在许多计算中使用这两个接口。 C 是实现前 2 的专用 Simulation。

编辑: 我重写了这个问题,也许现在它真的有意义了。

【问题讨论】:

设计看起来很糟糕......你想达到什么目的?从 B 到 A 的强制转换在逻辑上是不正确的。 坦克是带有大炮的载具。随机大炮可以驱动吗?随机车辆可以射击吗?这就是你的建议。 逻辑不正确?如果我将 A 转换为 C,然后将 C 转换为 B,我想我会得到与将 A 转换为 B 相同的结果? 您知道如果指针(或引用)是 C 的实例,标准允许您从 A 到 B 的 dynamic_cast 如果你使用static_cast编译会失败,如果你使用dynamic_cast你会得到一个空指针os an excetpion。如果你使用 reinterpret_cast 或 C 风格的演员,你会得到未定义的行为。我再说一遍——Subaro 车能不能仅仅因为坦克是车辆和大炮的结合而射击? 【参考方案1】:

我将说明我在评论中提出的观点。在兄弟姐妹之间进行强制转换是完全合法的,只要实际对象是从两者派生的。

#include<iostream>
using namespace std;

struct A
    virtual int auu()  return 41; 
;
struct B
    virtual int boo()  return 43; 
;

struct C : public A, public B
    int auu()  return 20; 
    int boo()  return 22; 
;

void take_B(B* bp)

    cout << bp->boo() << endl; // expected
    cout << "(The base class would say " 
        << bp->B::boo() << ")" << endl; // base class implementation

    A *ap = dynamic_cast<A*>(bp);
    if(!ap) 
    
        cerr << "weird, this cast should be possible!" << endl;
    
    else
    
        cout << ap->auu() << endl; // should work
        cout << "(The base class would say " 
            << ap->A::auu() << ")" << endl; // base class implementation
    


int main()

   C c;
   take_B(&c);

   cout << endl << "... and again:" << endl;
   // just to clarify: The actual pointer type is irrelevant.
   B *bp = &c;
   take_B(bp);

   return 0;

【讨论】:

我明白了,很好的示范。虽然如果 A 和 B 继承一个共同的,最好是空的类,我想做的事情就可以实现,对吧? (另一方面,我猜它最终会创建非常脆弱的代码) 不,当然不是!想想看——如果 D1 和 D2 都继承自一个空的 B,那么它们的“特长”将是无关的。例如,D1 对象不会在 D2 中定义 D2 的方法可能访问的数据成员。如果此类 D2 函数的代码在 D1 对象上执行,它将访问恰好位于 D2 中的该偏移量但在 D1 中没有对应关系的内存(更不用说更复杂的类布局问题)。如果你暴力调用((D2 *)d1p)-&gt;d2method(),你是在错误的对象上调用它。 D1 不是 D2。 (当然,两者都是 B。) 是的,当然,我明白了。实际上,这是一个可以在几秒钟内直观地解释的主题,而不是用指针思考:))

以上是关于是否可以通过单个指针访问多态类的不同祖先的虚拟方法?的主要内容,如果未能解决你的问题,请参考以下文章

详细的解释下类的封装性,抽象性,继承性和多态性。

访问祖先类的虚方法(直接访问祖先类的VMT,但是这种方法在新版本中未必可靠)

Java学习

对象的多态性

面向对象的过程继承封装多态;抽象类访问修饰符的使用引用类型强制转换方法重写@override与重载空指针异常super关键字

虚函数和虚拟继承的内存分布