强制引用基类:标准行为?

时间:2019-05-10 12:10:34

标签: c++ visual-c++ casting reference

我遇到以下情况:

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 ++的语言的编译器”执行以下操作:

  1. 创建一个Getter_AGetter_B对象。
  2. 拨打doSomething
  3. 删除创建的对象。

公开的问题是:该调用哪个?

在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 ++编译器将强制转换为基类的引用。

1 个答案:

答案 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();