2012-07-02 36 views
0

看看這個非常簡單的代碼:修改指針對象值在一個const方法

struct A { char* s; }; 

class B 
{ 
    A* a; 

    public: B(const char* s) : a(new A()) { 
     int len = strlen(s); 
     a->s = new char[len + 1]; 
     memcpy(a->s, s, len + 1); 
    } 

    ~B() { delete [] a->s; delete a; } 

    const char* c_str() const { return a->s; } 

    const B& to_upper() const { 
     char* x = a->s; 
     int len = strlen(x); 
     for (int i = 0; i < len; i++) 
     { 
      char k = x[i]; 
      if (k >= 'a' && k <= 'z') 
       x[i] -= 32; 
     } 
     a->say_hi(); 
     return *this; 
    } 
}; 

int main() { 
    B b = "hola mundo"; 
    printf("%s\n", b.to_upper().c_str()); 
} 

它的作品!我的問題是...爲什麼?

to_upper()方法是const並通過「a」修改值指針。好吧,我無法做類似「a = nullptr;」的事情因爲編譯器說:「你正試圖修改一個只讀對象」;但它可以讓我修改底層的值。這種行爲是否正確?在const方法中,不應該將「a」類型轉換爲「const A *」類似於「this」類型轉換爲「const B *」的方式?

謝謝!

+0

您在'B'的代理中使用了錯誤的刪除[]。 –

+0

nop,這是正確的;我創建了一個char數組。 – oopscene

+0

你不修改'B'對象。你沒有承諾不修改其他對象('a'指向的東西)。 – tmpearce

回答

6

方法的常量轉化爲*this對象的常量,意味着to_upper指針的內部爲const B *。這裏的所有都是它的。沒有更多,不少。例如,這種效果與您在C語言中看到的效果沒有什麼不同。它使指針this->a爲常量,但不會影響指針。

實際上,您要決定B的常量是否傳播到由this->a指向的A對象。這種語言給你充分的自由做出這個決定。它被稱爲「概念恆常性」(與「物理恆常性」或「邏輯恆常性」相對)。編譯器只觀察和強制執行邏輯常量,而OOP中關鍵字const的用途遠遠超出了這個範圍:它允許您在設計中實現概念常量的概念。

如果A對象被認爲是B的組成部分,那麼B的常量也應該表示爲A的常量。但這是你必須手動觀察和強制執行的(或者一些智能指針類可以幫助你做到這一點)。

如果A對象是這恰好是僅僅B引用一個獨立的對象,則B常量性不一定暗示的A常量性。

因爲編譯器不知道你想要實現什麼樣的對象關係,所以編譯器並沒有就此對你做出任何決定。在我的設計中,A對象實際上是B的組成部分,這意味着您不應聲明to_upperconst。這是一個修改功能。它將用戶感知的值改爲B的值。通過聲明to_upperconst您實質上是對用戶說謊。

+0

'編譯器只觀察和強制物理常量,不應該是'編譯器只觀察和強制執行邏輯常量'?由於物理常量AFAIK談論將對象放置在只讀存儲器中,這將在運行時強制執行。 –

+0

@Jesse Good:我使用的術語略有不同,但我同意你的說法更有意義。我修改了答案。 – AnT

1

const函數不能修改類成員。 'a指出'不是班級的成員。

+0

第一句話是不完全正確的,所以這個解釋失敗了。 –