2012-07-28 71 views
0

這會不會引起歧義?:C++:構造歧義

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

不,它不會。 – 2012-07-28 21:24:35

+4

也許不在編譯器中。但是3D矢量真的是2D矢量嗎? – 2012-07-28 21:26:07

+0

它不會拯救你從類似'Vector3D x,y(static_cast (x));'雖然... – 2012-07-28 21:27:26

回答

4

更新:看來,提問者已經從問題擦洗類名。這是寫這個答案的原始代碼片段:

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。這在數學上不合邏輯。

+1

@Casey:編譯器會告訴你是否存在歧義,你需要做的就是編譯代碼並測試自己。 – 2012-07-28 23:03:28

1

操作&生成引用。

在你的情況下,第一種類型是對Vector3D類型的引用,另一種是對Vector2D類型的引用,因此它們是不同的類型。

由於它們是不同的類型,它們將使您的構造函數的簽名不同,並且它們不會產生歧義。

答案是否定的

+0

>運算符(地址)產生指針,而不是引用 – 2012-07-28 21:55:29

+0

@CharlesBailey我不明白你正在提出一個問題或一個陳述,但在這種情況下,&運算符將生成一個引用。 – user827992 2012-07-28 22:09:43

+0

我在查詢你的陳述,也許我不瞭解你的陳述的上下文。不是操作符,它是聲明器的一部分,與聲明中可用於聲明指針的'*'類似,但作爲操作符使用時,可以有效地除去其操作數的「指針性」,取消引用指針 – 2012-07-28 22:15:39

2

在重載構造函數之間進行選擇時,它們引用基本類型和派生類型,通常不存在歧義。

如果參數的類型派生自基類型(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);