2015-06-28 105 views
3

這似乎是一個相當武斷的限制。 像C函數那樣的常規方法不是指向實例的參數嗎?爲什麼C++不允許向類中添加新的方法?

如果是這樣,我不明白爲什麼添加新方法應該強制我重新編譯我的課程的其餘部分。爲什麼不允許通過單獨的修訂頭和單獨的修改實現來添加方法。

+2

TBH向類中添加方法應該是一個相對罕見的事件(假設您的項目有* design *階段)。 – Galik

+2

@Galik真的,但他似乎在問一個關於C++技術特性的問題,而不是它的設計理念。 –

+3

這聽起來像只是等待發生的ODR違規行爲。例如。重載分辨率在看到額外方法的轉換單元和不轉換單元之間的工作方式會有所不同。 –

回答

1

我想起了幾件事情。一方面,您需要聲明方法的範圍,我認爲這就是允許您按照您的建議添加新操作符的原因。

另一方面,你有繼承問題。編譯器需要知道所有的虛擬方法,以便將它們包含在vtable中。

5

考慮這個例子

// in some header 

    struct X 
    { 
     float func(float); 
    }; 

    // and in another source file 

    void caller() 
    { 
     X x; 
     std::cout << x.func(2);  // will call X:func(float) 
    } 

現在假設我們決定要添加的func()的新版本接受一個int

 // in some header 

    struct X 
    { 
     float func(float); 
     void func(int); 
    }; 

    // and in another source file 

    void caller() 
    { 
     X x; 
     std::cout << x.func(2); 
    } 

如果caller()功能沒有重新編譯,就沒有辦法註冊,它被調用函數發生了變化 - 它會繼續呼籲在構建X::func(float)

然後 - 在事實之後可能有幾個月(或在大系統中,年) - 另一個開發人員對與caller()相同的源文件中的某個函數完全無關的更改。因此,源文件得到重建...最後。突然間,那個人發現caller()將不能編譯 - 錯誤消息與他或她正在執行的代碼更改沒有任何關係。

所有這些都發生在違規者 - 引入新成員函數但沒有觸發重新編譯和重建的程序員 - 無處可見時。

留下的開發人員留下來解決這個爛攤子。由於沒有關於究竟是什麼導致問題的信息,爲什麼它昨天工作,但不是今天工作,沒有真正的線索,如何妥善解決它......但仍然是誰將負責。

這只是C++中「任意限制」會阻止的許多問題之一。

0

由於deviantfan說,它真的沒有真正的問題(假設你想添加一個普通的(非虛擬的)方法)。

$ for file in X.hh X.cc X-1.hh X-1.cc main.cc; do echo -e "\n//--------------//$file"; cat "$file"; done                               

//--------------//X.hh 
//X.hh 
struct X { 
    int foo(int); 
}; 

//--------------//X.cc 
//X.cc (available as X.o) 
#include "X.hh" 
int X::foo(int a){ return a+1; } 

//--------------//X-1.hh 
//X-1.hh 
//copy X.hh and amend it 
struct X { 
    int foo(int); 
    int bar(int); 
}; 

//--------------//X-1.cc 
//X-1.cc 
#include "X-1.hh" 
int X::bar(int a){ return a+2; } 

//--------------//main.cc 
//main.cc 
#include "X-1.hh" 
//^the latest definition 
#include <iostream> 
int main(){ 
    using namespace std; 
    X x; 
    cout << x.foo(1) << endl; 
    cout << x.bar(1) << endl; 

而現在的建築部分:

$ make {X,X-1,main}.o 
$ g++ {X,X-1,main}.o #links correctly! 
$ ./a.out 
2 
3 

工程,即使這些方法訪問類/結構變量。

TL; DR:

如果使用僅由瑣碎方法加法裝置(沒有過載或虛函數改變使用依賴跟蹤#include s個文件構建系統,可以make --assume-old一個報頭(或touch --date='10 minutes ago' changed_header.hh) ),因爲所有依賴於類實例方法的舊子集的舊對象文件都不需要重新編譯。

此外,拉斐爾Miedl指出,有一個http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4474.pdf ,基本上允許通過點語法來調用獨立職能的建議,所以這基本上等同於重新打開類瑣碎的功能補充。

重載函數並不是一個真正的問題,因爲您總是會使用#include一個類的特定表示(或者相同的類+一組特定的點語法可映射的獨立函數),您可以使用不同版本的相同的類(相當於有一個類+不同的點語法可映射獨立函數集)。 (與虛擬函數不同,因爲對象實例中的vtable和vtable指針)。

相關問題