這會不會引起歧義?: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