【问题标题】:C++: Constructor ambiguityC++:构造函数歧义
【发布时间】:2012-07-28 21:22:02
【问题描述】:

这会引起歧义吗?:

class A { ... };
class B : public A {
//...
B(const B& b);
B(const A& a);
//...
};

【问题讨论】:

  • 也许与编译器无关。但是 3D 向量真的是 2D 向量吗?
  • 它不会让你免于做类似Vector3D x, y(static_cast<Vector2D&>(x)); 这样的事情...

标签: c++ constructor ambiguity ambiguous


【解决方案1】:

更新:提问者似乎已从问题中删除了类名。这是编写此答案的原始代码:

class Vector2D { ... };
class Vector3D : public Vector2D {
//...
Vector3D(const Vector2D& b);
Vector3D(const Vector3D& a);
//...
};

我之前说“不”,但我改变了主意。这是模棱两可的,我想不出有充分理由让Vector3D 继承自Vector2D

从数学的角度来看,2D 向量空间可以扩展到 3D 向量空间,但有许多扩展可供选择——它们不是唯一的。因此,当您创建一个从 2D 向量类继承的 3D 向量类时,您正在使 3D 空间中的 2D 空间的一个嵌入成为“特权”,而所有其他嵌入则处于劣势。我认为这不是特别有用。

您正在做的另一件事是您说“每个 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:编译器会告诉你是否有歧义,你需要做的就是尝试编译代码并自己测试。
【解决方案2】:

在采用基类和派生类型引用的重载构造函数之间进行选择时,通常不会有歧义。

如果参数是派生自基类型 (A) 但不是派生类型 (B) 或派生自派生类型的类型,那么显然只有引用基的构造函数是一场比赛。

如果参数是派生类型,则调用采用基类的构造函数所需的转换需要派生到基类型,此时调用引用派生类型的构造函数只需要一个标识转换,所以后者是更好的匹配。

如果参数是从派生类型 (B) 派生的类,那么采用派生类型 (B) 的构造函数仍然是更好的匹配,因为标准规定绑定到派生类型的引用比绑定到该类型基的引用要好。 (ISO/IEC 14882:2011 13.3.3.2 / 4 - 对隐式转换序列进行排名 [over.ics.rank])

如果你足够努力,显然你仍然会产生歧义。

例如

struct S {
    operator A() const;
    operator B() const;
};

S s;
B b(s);

【讨论】:

    【解决方案3】:

    运算符& 生成引用。

    在您的情况下,第一种类型是对 Vector3D 类型的引用,另一种是对 Vector2D 类型的引用,因此它们是不同的类型。

    由于它们是不同的类型,它们会使你的构造函数的签名不同,而且它们也不会产生歧义。

    答案是否定的。

    【讨论】:

    • & 运算符(地址)生成的是指针,而不是引用??
    • @CharlesBailey 如果您提出问题或陈述,我不明白,但在这种情况下,& 运算符将生成参考。
    • 我在查询你的陈述,也许我没有理解你陈述的上下文。引用声明中的& 不是运算符,它是声明符的一部分。类似于*,它可以在声明中用于声明指针,但当用作运算符时,它会有效地删除其操作数的“指针性”,从而取消对指针的引用。
    猜你喜欢
    • 1970-01-01
    • 2017-12-31
    • 1970-01-01
    • 1970-01-01
    • 2014-01-13
    • 1970-01-01
    • 1970-01-01
    • 2020-06-12
    • 1970-01-01
    相关资源
    最近更新 更多