这会不会引起歧义?:C++:构造歧义
class A { ... };
class B : public A {
//...
B(const B& b);
B(const A& a);
//...
};
这会不会引起歧义?:C++:构造歧义
class A { ... };
class B : public A {
//...
B(const B& b);
B(const A& a);
//...
};
更新:看来,提问者已经从问题擦洗类名。这是写这个答案的原始代码片段:
class Vector2D { ... };
class Vector3D : public Vector2D {
//...
Vector3D(const Vector2D& b);
Vector3D(const Vector3D& a);
//...
};
我之前说过“不”,但我改变了主意。这是模棱两可的,我想不出有一个很好的理由让Vector3D
继承自Vector2D
。
从数学的角度来看,2D矢量空间可以扩展到3D矢量空间,但有很多扩展可供选择 - 它们不是唯一的。因此,当您制作从2D矢量类继承而来的3D矢量类时,您正在将3D空间中的2D空间嵌入到“特权”的3D空间中,并且所有其他嵌入均较差。我认为这不是特别有用。
你正在做的另一件事是你说“每个3D矢量都是2D矢量”,这实在是太愚蠢了。比如,也许你编写一个函数:
// Compute the angle between two vectors
double angle(Vector2D x, Vector2D y);
让我们假设你忘记写的版本3D矢量。现在,编译器将无法给您一个错误信息:相反,您的3D矢量将使用您在创建类时选择的“特权”投影投影到2D空间中,并且您将得到错误的答案。现在假设你添加了另一个功能:
// Compute the angle between two 3D vectors
double angle(Vector3D x, Vector3D y);
现在,仍然存在问题。
Vector3D x = ...;
Vector2D y = ...;
double a = angle(x, y);
这将使用x的2D投影,并且您不会收到编译器警告。你只会得到错误的答案。
摘要:这是最糟糕的一种模糊性:它是一种模糊性,编译器会给你一个你不期待的答案。
Vector3D不应该继承自Vector2D。这在数学上不合逻辑。
@Casey:编译器会告诉你是否存在歧义,你需要做的就是编译代码并测试自己。 – 2012-07-28 23:03:28
操作&
生成引用。
在你的情况下,第一种类型是对Vector3D类型的引用,另一种是对Vector2D类型的引用,因此它们是不同的类型。
由于它们是不同的类型,它们将使您的构造函数的签名不同,并且它们不会产生歧义。
答案是否定的
>运算符(地址)产生指针,而不是引用 – 2012-07-28 21:55:29
@CharlesBailey我不明白你正在提出一个问题或一个陈述,但在这种情况下,&运算符将生成一个引用。 – user827992 2012-07-28 22:09:43
我在查询你的陈述,也许我不了解你的陈述的上下文。不是操作符,它是声明器的一部分,与声明中可用于声明指针的'*'类似,但作为操作符使用时,可以有效地除去其操作数的“指针性”,取消引用指针 – 2012-07-28 22:15:39
在重载构造函数之间进行选择时,它们引用基本类型和派生类型,通常不存在歧义。
如果参数的类型派生自基类型(A
),但不是派生类型(B
)或衍生自派生类型的派生类型,那么显然只有参考base的构造函数是匹配项。
如果参数是派生类型,那么调用构造函数获取基类所需的转换需要派生类到基类型,此时调用构造函数的参考派生类型只需要一个身份转换,所以后者是更好的匹配。
如果参数是从所述派生类型(B
)派生的类的,则构造服用派生类型(B
)仍然是一个更好的匹配,因为标准说,结合到派生类型的基准优于绑定到该类型的基准的引用。 (ISO/IEC 14882:2011 13.3.3.2/4 - 隐式转换序列排序[over.ics.rank])
显然,如果您足够努力,仍然可以产生歧义。
E.g.
struct S {
operator A() const;
operator B() const;
};
S s;
B b(s);
不,它不会。 – 2012-07-28 21:24:35
也许不在编译器中。但是3D矢量真的是2D矢量吗? – 2012-07-28 21:26:07
它不会拯救你从类似'Vector3D x,y(static_cast(x));'虽然... –
2012-07-28 21:27:26