2010-05-29 22 views
2

也許更好的是:爲什麼標準要求在這些情況下轉發到基類? (耶 - 爲什麼 - 因爲?)標準中的哪些位置正在轉發到這些情況下所需的基類?

class B1 { 
public: 
    virtual void f()=0; 
}; 
class B2 { 
public: 
    virtual void f(){} 
}; 
class D : public B1,public B2{ 
}; 
class D2 : public B1,public B2{ 
public: 
    using B2::f; 
}; 
class D3 : public B1,public B2{ 
public: 
    void f(){ 
     B2::f(); 
    } 
}; 
D d; 
D2 d2; 
D3 d3; 

MS給出:

sourceFile.cpp 
sourceFile.cpp(24) : error C2259: 'D' : cannot instantiate abstract class 
     due to following members: 
     'void B1::f(void)' : is abstract 
     sourceFile.cpp(6) : see declaration of 'B1::f' 
sourceFile.cpp(25) : error C2259: 'D2' : cannot instantiate abstract class 
     due to following members: 
     'void B1::f(void)' : is abstract 
     sourceFile.cpp(6) : see declaration of 'B 

,同樣爲MS編譯器。

可能購買第一種情況下,d。但是在D2-f中使用聲明定義的明確地爲,爲什麼這不足以滿足需要填充vtable的編譯器?

標準在哪裏這種情況下定義?

的效應初探添加回答

對於下面的答案我已經接受:

這個問題似乎不爲什麼在規範中的錯誤? - 如果有一個具有一系列非虛擬f()的繼承層次結構,派生類中的使用通過使用語句來確定,並且將基類中的f的decl改爲虛擬,那麼可以改變在派生類中調用f並使用語句來選擇它們的f。這是一個我不知道的C++「gotcha」。它可能是語言的一部分,但這種「遠距離行動」使我感到不安,對我來說似乎違反了某種正確性/維護原則(我現在還不能完全闡明)。

但是我可以舉一個例子:

#include <iostream> 
using std::cout; 


namespace NonVirtual_f{ 

class C0 { 
public: 
    void f(){cout<<"C0::f()"<<'\n';} 
}; 

class C1 : public C0{ 
public: 
    void f(){cout<<"C1::f()"<<'\n';} 
}; 

class C2 : public virtual C1{ 
public: 
    void f(){cout<<"C2::f()"<<'\n';} 
}; 

class D3 : public virtual C1, public C2{ 
public: 
    using C1::f; 
}; 


}//namespace NonVirtual_f 

namespace Virtual_f{ 


class C0 { 
public: 
    virtual void f(){cout<<"C0::f()"<<'\n';} 
}; 

class C1 : public C0{ 
public: 
    void f(){cout<<"C1::f()"<<'\n';} 
}; 

class C2 : public virtual C1{ 
public: 
    void f(){cout<<"C2::f()"<<'\n';} 
}; 

class D3 : public virtual C1, public C2{ 
public: 
    using C1::f; 
}; 



}//namespace Virtual_f 




int main(int argc,const char* const*argv){ 

    NonVirtual_f::D3 nv3; 
    nv3.f(); 

    Virtual_f::D3 v3; 
    v3.f(); 

    return 0;  
} 

從那裏的輸出:

C1::f() 
C2::f() 

所有這些改變是在C0 f的虛擬性。特別地,一旦在基類f的非虛擬性被選擇,它不能在不維護問題改變,如果一些派生類(即在一般一個不能知道)已經「被覆蓋」如在示例就在上面。

如果用「好了,不重寫的方式在非虛擬的情況下」對抗,我同意這是不好的做法,但這似乎遠遠不止這些。對我來說,語言應該:

不允許在非虛擬:: D3的使用(目前不可能的,因爲可能有其他重載F公司在把[除非在功能的情況下使用允許簽名])

或使用的完全功能和力語句

不允許轉發

具有實際運用覆蓋在所有情況下

允許功能的一些語法聲明(基本使用功能),如:

void f(*signature*) = C2::f; 

究竟什麼我錯過了? 有人能想出一個方案來闡明標準中這種選擇的「原因」嗎?

+0

供參考:所張貼的錯誤是從Visual C++ :-) – 2010-05-29 02:46:20

+0

EDG 「sourceFile.cpp」,行24:錯誤: 對象抽象類型「D」不允許爲: 純虛函數「B1 :: f」沒有覆蓋 D d; ^ 「sourceFile.cpp」,第25行:錯誤:抽象類型的 對象 「D2」 是不允許的: 純虛函數 「B1 :: F」 不具有置換器 D2 D2; ^ – pgast 2010-05-29 02:55:52

+0

您可能已經知道了這一點,但只是作爲參考,如果您已將f()= 0放入B1和B2的虛擬基類中,則D將起作用。看到姐妹班代表團:http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.10 – 2011-09-27 21:34:13

回答

3

C++標準說,在10.3節/ 2:

The rules for member lookup (10.2) are used to determine the final overrider for a virtual function in the scope of a derived class but ignoring names introduced by using-declarations.

所以,即使您使用using B2::f;帶來B2::f()到派生類,它不考慮重寫B1::f()

因此,D2是抽象的,因爲第10.4節/ 4:

A class is abstract if it contains or inherits at least one pure virtual function for which the final overrider is pure virtual.

+0

簡而言之。 +1,如果可以的話更多。 – 2010-05-29 02:51:40

+0

爲什麼這在規格中似乎不是一個錯誤? - 如果有一個具有一系列非虛擬f()的繼承層次結構,派生類中的使用通過使用語句來確定,並且將基類中的f的decl改爲虛擬,那麼可以改變在派生類中調用f並使用語句來選擇它們的f。這是一個我不知道的C++「gotcha」。它可能是語言的一部分,但這種「遠距離行動」使我感到不安,對我來說似乎違反了某種正確性/維護原則(我現在還不能完全表述) – pgast 2010-05-29 16:08:41

相關問題