2013-03-13 98 views
14

考慮:現在私人基類和多重繼承

struct A { int x;}; 
struct B : A {}; 
struct C : private A {}; 

,符合市場預期,代碼

struct D : C 
{ 
    D() { C::x = 2; } 
}; 

int main() { D d; } 

不會編譯:

test2.cc: In constructor ‘D::D()’: 
test2.cc:1:16: error: ‘int A::x’ is inaccessible 
test2.cc:7:12: error: within this context 

現在,如果我做

struct D : B, C 
{ 
    D() { C::x = 2; } 
}; 

int main() { D d; } 

然後錯誤消失!是不是A::x也應該是無法訪問?這裏的解釋是什麼?

我正在使用gcc version 4.7.2 (GCC),linux x86_64,如果這很重要。

編輯:它不鏘3.2編譯:clang 3.2

但用gcc 4.7.2作用:gcc 4.7.2

+0

編譯[有](http://ideone.com/clone/VvWyUW)(儘管同樣的編譯器)。似乎GCC的錯誤呢? – 2013-03-13 23:37:44

+1

有趣的是:相同的編譯器,不同的結果。無論如何,我無法想象任何東西 – 2013-03-13 23:39:34

+0

g ++ 4.7.2成功地在兩個位置編譯相同的源代碼。 – Aneri 2013-03-13 23:39:51

回答

10

這肯定是一個錯誤。沒有理由繼承B類,也應該改變C的成員的可訪問性。

甚至沒有GCC 4.8.0(測試版)似乎已經解決了這個問題。另一方面,Clang 3.2和ICC 13.0.1,correctly refuse to compile this code

+1

@ValeriAtamaniouk:什麼? – 2013-03-14 00:36:22

+2

@ValeriAtamaniouk:我不知道,'C :: x'很清楚,範圍是'C'。 – GManNickG 2013-03-14 00:38:17

+0

@GManNickG:你確定嗎?這個名字是'A :: x'。它沒有命名'C'子對象。如果你想命名'C'子對象的成員,使用'C * p = this; p-> x' – 2013-03-14 00:41:00

-1

我不知道確切原因,但我知道這一點:

,當你在這樣一個菱形圖案使用多重繼承,你將有基類的多個副本中,你得到的對象D.

在你的情況下,對象D有2個成員命名爲A :: x,這可能會引起編譯器的混淆。

這是被稱爲Diamon Problem

+0

鑽石問題與這個問題有什麼關係?他創建一個鑽石形狀的繼承圖的唯一場景是第二個,他說工作正常! – 2013-03-14 00:23:48

3

答案是鐺是正確的。但是,根據標準,代碼也可能會失敗。

如果你看看11.2p5它有一個相關的說明(是的,我知道筆記非規範):

[注:這個類可以是明確的,例如,當一個合格的-ID是使用, 或隱式,例如,當使用類成員訪問運算符(5.2.5)時 (包括添加了隱含「this->」的情況)。 如果012xx成員訪問運算符和合格ID都用於命名成員 (如p->T::m中所示),則命名該成員的類是由 指定的類。qualified-id的嵌套名稱說明符即T)。末端注意 ]

這是什麼意思音符,是,如果你然後添加到this->C::x = 2;C是類命名的成員和gcc 4.7.2 correctly fails when this is the case

現在的問題是誰是爲C::x命名成員的班級? 該naming class由相同11.2p5指定:由類

到成員的接入會受到影響,其中所述構件是 命名。 這個命名類是查找並找到成員名稱爲 的類。

現在,類成員名稱查找在10.2指定,閱讀這一切後,我的結論是x是子對象集工會按:

否則,新的S(f,C)是一個查找集,其中共享集 聲明和子對象集的聯合。

這意味着根據構件查找規則x可以是從BA!這使得代碼不良形成:Name lookup can result in an ambiguity, in which case the program is ill-formed. 然而,這種不確定性可以被解析爲每10.2p8:

歧義往往可以通過與同級車 名排位賽的名稱來解決。

而且從Clang source,我們可以看到這是他們選擇這樣做:

// If the member was a qualified name and the qualified referred to a 
// specific base subobject type, we'll cast to that intermediate type 
// first and then to the object in which the member is declared. That allows 
// one to resolve ambiguities in, e.g., a diamond-shaped hierarchy such as: 
// 
// class Base { public: int x; }; 
// class Derived1 : public Base { }; 
// class Derived2 : public Base { }; 
// class VeryDerived : public Derived1, public Derived2 { void f(); }; 
// void VeryDerived::f() { 
//  x = 17; // error: ambiguous base subobjects 
//  Derived1::x = 17; // okay, pick the Base subobject of Derived1 
// } 

但是,請注意上述報價的措辭canoften can be resolved。這意味着他們不一定要解決。所以,我認爲根據標準,代碼應該失敗,因爲模糊或作爲私人成員訪問失敗。

編輯

有關於can解釋一些競爭和是否一個歧義發生在這裏。我發現Defect report 39. Conflicting ambiguity rules談到了這個問題。

+0

我不確定我是否同意你的閱讀,你看到10.1 p5的例子嗎?似乎很清楚,即使沒有「this->」,也不會有任何含糊之處。 (這個案例幾乎與問題中引用的和你的回答完全一樣。) – 2013-03-15 00:20:15

+0

@StephenLin:注意'可以使用'的措詞。我把它理解爲它​​不是強制性的。 – 2013-03-15 00:23:52

+0

我相信這裏的「can」這個詞意味着,如果qual-id解析爲僅有一個該名稱的成員的子對象(但可能不是,如果給定的限定id仍然有多個子對象具有相同的成員名稱),而不是標準允許判斷是否解決它。如果標準在基本的編譯時語義問題上真正賦予實現自由裁量權,而不是簡單地未指定的運行時行爲,我會發現它非常不尋常。 – 2013-03-15 00:23:53