我有如下情况:
class Getter
{public: virtual void doSomething {std::cout<<"Nothing";};
};
class Getter_A: public Getter
{public: void doSomething {std::cout<<"A";};
};
class Getter_B: public Getter
{public: void doSomething {std::cout<<"B";};
};
然后我有一段代码,我想在其中使用其中一个 Getter 东西。因此,用英语,我会这样:
{Getter & getter=wantA?Getter_A():Getter_B;
getter.doSomething();
};
当然,在 C++ 中这不太可行,因为三元运算符不够聪明,无法寻找公共(public)基类,所以我这样做:
{Getter & getter=wantA?(Getter &)Getter_A():(Getter &)Getter_B;
getter.doSomething();
};
这是优雅和可读的。问题是它是否适用于 C++。由于没有 C++ 编译器,而且我在引用书中找不到明确的答案,所以我在这里问。
共同点:我试过的“类似 C++ 的语言的编译器”执行以下操作:
- 创建一个
Getter_A
或一个Getter_B
对象。 - 调用
doSomething
。 - 删除创建的对象。
悬而未决的问题是:要调用哪个 doSomething?
Mac 上的 Clang 调用 Getter_A::doSomething()
或 Getter_B::doSomething()
。因此,在幕后,Getter&
引用是对 Getter_A
对象或 Getter_B
对象的引用。
Visual C++ 6.0 调用 Getter::doSomething()
。因此,在幕后,它从创建的对象中剥离了 Getter_A
ness 并引用了一个裸露的 Getter
对象。如果 Getter::doSomething
是纯的而不是有一个主体,这将变得更加壮观。
现在,Visual C++ 6.0 以不是编译 C++ 而是完全不同的同名语言而闻名。然而,最好知道 C++ 本身(与这个或那个编译器编写者对 C++ 的看法相反)是否期望基类引用继续是对原始对象的引用它所有光彩夺目的虚拟性,或者在这种情况下,微软是否正确地在转换其引用时将对象剥离裸体。
我提出并测试的工作轮是:
{Getter_A a; Getter_B b;
Getter &getter=*(wantA?(Getter *)&a:&b);
getter.doSomething();
}
因为编译器尊重指针的隐私,所以似乎到处都是安全的。但这是一种有点困惑的语言,最好知道真正的、符合标准的 C++ 编译器会如何处理对基类的引用转换。
最佳答案
我认为您的“优雅且可读”的方法有错字,而您打算阅读
{Getter & getter=wantA?(Getter &)Getter_A():(Getter &)Getter_B(); getter.doSomething(); };
(请注意 Getter_B
之后的 ()
,您的描述中缺少它)。
在任何情况下,这都会产生未定义的行为,因为所选对象在语句 getter.doSomething()
之前不再存在。因此,测试调用了哪个 doSomething()
是学术性的——即使两个编译器给出不同的结果,它们都是正确的。
您需要做的是确保您使用的对象在调用之前继续存在。
有多种方法,例如(本质上)您的“解决方法”。
Getter_A a;
Getter_B b;
Getter &getter = wantA ? (Getter &) a : (Getter &) b;
getter.doSomething();
或(更明确地)
Getter_A a;
Getter_B b
Getter &ra(a), &rb(b);
Getter &getter = wantA ? ra : rb;
getter.doSomething();
关于c++ - 转换对基类的引用 : standard behaviour?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56077473/