C++强制运算符重载和多态性
C++ cast operator overloading and polymorhism
我对C++的这种行为感到困惑:
struct A {
virtual void print() const { printf("an"); }
};
struct B : public A {
virtual void print() const { printf("bn"); }
};
struct C {
operator B() { return B(); }
};
void print(const A& a) {
a.print();
}
int main() {
C c;
print(c);
}
那么,测试是,程序的输出是什么——a还是b?答案是a。但是为什么呢?
这里的问题是C++03标准中的一个bug/misfeature/漏洞,不同的编译器试图以不同的方式修复这个问题。(这个问题在C++11标准中不再存在。(
两个标准的第8.5.3/5节规定了如何初始化引用。这是C++03版本(列表编号是我的(:
对类型
cv1 T1
的引用由类型cv2 T2
的表达式初始化如下:
如果初始值设定项表达式
- 是左值(但不是位字段(,并且"cv1 T1"是与"cv2 T2"兼容的参考,或者
- 具有类类型(即
T2
是类类型(,并且可以隐式转换为类型cv3 T3
的左值,其中cv1 T1
是与cv3 T3
兼容的引用然后在第一种情况下引用直接绑定到初始值设定项表达式lvalue,在第二种情况下,引用绑定到转换的lvalue结果。
否则,引用应为非易失性常量类型(即
cv1
应为const
(。如果初始值设定项表达式是右值,
T2
是类类型,并且cv1 T1
是与cv2 T2
兼容的引用,则引用以以下方式之一绑定(选项由实现定义(:
- 引用绑定到由右值表示的对象(见3.10(或该对象中的子对象
- 创建一个类型为
cv1 T2
[sic]的临时对象,并调用一个构造函数将整个右值对象复制到临时对象中。引用绑定到临时对象或临时对象中的子对象将用于制作副本的构造函数应是可调用的,无论副本是否实际完成。
否则,将使用非引用副本初始化的规则(8.5(从初始值设定项表达式创建并初始化类型为
cv1 T1
的临时项。然后将引用绑定到临时项。
手头的问题涉及三种类型:
- 要创建的引用的类型。标准(两个版本(将这种类型表示为
T1
。在这种情况下,它是struct A
- 初始值设定项表达式的类型。标准将这种类型表示为
T2
。在这种情况下,初始化器表达式是变量c
,因此T2
是struct C
。请注意,由于struct A
与struct C
不兼容引用,因此无法将引用直接绑定到c
。需要一个中间体 - 中间体的类型。标准将这种类型表示为
T3
。在这种情况下,这是struct B
。注意,将转换运算符C::operator B()
应用于c
将把左值c
转换为右值
我标记为1.1和3的初始化被取消,因为struct A
与struct C
不兼容。需要使用转换运算符C::operator B()
。1.2 out因为这个转换运算符返回一个右值,所以这个规则1.2 out。剩下的就是选项4,创建一个类型为cv1 T1
的临时。严格遵守2003年版本的标准迫使为这个问题设立两个临时机构,尽管只有一个就足够了。
2011年版本的标准通过将选项3替换为来解决问题
如果初始值设定项表达式
- 是xvalue、类prvalue、数组prvalue或函数lvalue,
cv1 T1
是引用-与cv2 T2
兼容,或- 具有类类型(即,
T2
是类类型(,其中T1
不是与T2
相关的引用,并且可以隐式地转换为类型为cv3 T3
的xvalue、类prvalue或函数lvalue,其中,cv1 T1
是与cv3 T3
兼容的引用则引用在第一种情况下绑定到初始值设定项表达式的值,在第二种情况下则绑定到转换的结果(或者,在任何一种情况下,绑定到适当的基类子对象(。在第二种情况下,如果引用是右值引用,并且用户定义的转换序列的第二个标准转换序列包括左值到右值的转换,则程序格式错误。
似乎gcc编译器家族选择了严格遵守而非意图(避免创建不必要的临时性(,而其他打印"b"的编译器则选择了对标准的意图/更正。选择严格遵守并不一定值得称赞;在2003版本的标准(例如std::set
(中,gcc家族选择了理智而不是严格遵守。
- 将多态性与运算符 + 重载模板化类结合使用.如何实现基类?
- C++模板方法重载和具有多态性的类访问
- C++ 中多态性和函数重载之间的区别
- 如何用复数和多态性重载运算符
- 正确执行运算符重载和多态性
- 多态性和方法重载在C++中几乎是一样的
- 在C++中创建一个具有多态性和操作重载的模板
- 如果重载函数仅被部分重写,则多态性不起作用
- 动态多态性和运算符重载的真实示例
- C++运算符重载和多态性
- 具有不同签名的多态性和重载函数
- C++:多态性和运算符重载
- c++中的多态性和运算符重载混淆
- c++中的操作符重载和多态性
- 重载父函数是否会规避多态性?
- c++中的动态多态性和函数重载
- Operator=带多态性的重载
- c++多态性和重载
- 重载运算符[]多态性
- C++强制运算符重载和多态性