我遇到以下情况:
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 ++中这将无法正常工作,因为三元运算符不够聪明,无法寻找通用的基类,所以我这样做:
{Getter & getter=wantA?(Getter &)Getter_A():(Getter &)Getter_B;
getter.doSomething();
};
这是优雅且易读的。问题是它是否可以在C ++中工作。由于没有C ++编译器,并且由于我无法在参考书中找到明确的答案,所以我在这里问。
共同点:我尝试过的“类似于C ++的语言的编译器”执行以下操作:
Getter_A
或Getter_B
对象。 doSomething
。公开的问题是:该调用哪个?
在Mac上,C叫Getter_A::doSomething()
或Getter_B::doSomething()
。因此,在幕后,该Getter&
引用是对Getter_A
对象或Getter_B
对象的引用。
Visual C ++ 6.0调用Getter::doSomething()
。因此,在幕后,它从创建的对象中剥离Getter_A
,并改为引用裸露的Getter
对象。如果将Getter::doSomething
做成纯净的而不是有身体的话,这将变得更加壮观。
现在,Visual C ++ 6.0以不编译C ++但使用相同名称的完全不同的语言而闻名。但是,最好知道 C ++本身(与之相反,还是编译器作者对C ++的想法)期望基类引用继续作为对中原始对象的引用。所有其光荣的虚拟性,或者Microsoft在这种情况下是否正确,在投射其引用时将其裸露。
我提出并测试的工作周期是:
{Getter_A a; Getter_B b;
Getter &getter=*(wantA?(Getter *)&a:&b);
getter.doSomething();
}
由于编译器尊重指针的私密性,因此似乎在任何地方都是安全的。但这是一门凌乱的语言,最好知道真正的,符合标准的C ++编译器将强制转换为基类的引用。
答案 0 :(得分:3)
我认为您的“优雅且易读”的方法有错别字,您打算阅读
{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();