2010-10-28 131 views
10

我想知道是否可以從const成員函數中調用非const成員函數。在下面的例子中,First給出了一個編譯器錯誤。我明白爲什麼會出現錯誤,我想知道是否有辦法解決此問題。從const成員函數調用非const成員函數

class Foo 
{ 
    const int& First() const 
    { 
     return Second(); 
    } 

    int& Second() 
    { 
     return m_bar; 
    } 

    int m_bar; 
} 

我真的不想討論這樣做的智慧,我很好奇,如果它甚至可能。

+3

你不是第一個:http://stackoverflow.com/questions/856542/elegant-solution-to-duplicate-const-and-non-const-getters – 2010-10-28 21:13:27

+0

謝謝直到,沒有出現我的搜索 – Steve 2010-10-28 21:26:48

回答

28
return (const_cast<Foo*>(this))->Second(); 

然後安靜地哭泣。

+0

如果這些函數具有相同的名稱,該怎麼辦? const int&GetBar()const; int&GetBar(); – phandinhlan 2015-04-24 22:15:56

+0

你可以重載一個const的函數,所以它會簡單的工作。 – user3063349 2016-05-10 10:21:59

10

這是可能

const int& First() const 
{ 
    return const_cast<Foo*>(this)->Second(); 
} 

int& Second() { return m_bar; } 

我不會推薦;這是醜陋和危險的(任何使用const_cast是危險的)。

這是更好地移動儘可能多的通用功能,你可以進入輔助功能,然後讓const和non-const成員函數每個做盡可能少的工作,因爲他們需要。

對於這樣一個簡單的訪問器,它就像從兩個函數調用一個函數一樣簡單到return m_bar;

+0

或者只是把'int&Second()'變成'int&Second()const'。 non-'const'成員函數在調用'Second()'時沒有問題,但現在'const'成員函數也可以在沒有任何jiggery-pokery的情況下調用它。 – 2010-10-28 21:30:21

+0

@Jeremy:你認爲我們如何返回一個非const引用給成員呢? – GManNickG 2010-10-28 21:32:22

+0

@GMan:Touché。你不能沒有聲明'm_bar'作爲'mutable int'。 @Fred Larson的推薦是相當不錯的,但是它帶領的方向 - 一旦「const」修改並且一旦沒有 - 就不會那麼愉快地編寫每個有福的訪問者兩次。 – 2010-10-28 21:39:16

3

通過的const的定義,函數不應修改一個對象的狀態。但是如果它調用另一個非const成員,那麼該對象的狀態可能會發生變化,因此它是不允許的。

我知道你說你不想聽到這個,但我認爲這是別人在問題所發生的重要。

2

超載對const

const int& Second() const 
{ 
    return m_bar; 
} 

您可以添加此方法並保持原有的非const版本。

1

迭代器是在此類似,使一個有趣的研究。

常量迭代器通常是「非常量」迭代器的基礎,並且您經常會發現const_cast<>()或C風格強制轉換用於從子類中的帶有訪問器的基類中丟棄常量。

編輯: 評論是

我有一個拉鍊迭代器,其中常量一個從非const

繼承這通常會是錯的傳承結構(如果你說什麼我認爲你是),原因是孩子不應該比父母限制少。

說你有一些算法把你的拉鍊迭代器,一個const迭代器傳遞給非const的會是合適的呢?

,如果你有一個const容器,只能請它替一個const迭代器,但隨後的常量迭代從迭代器派生,所以你只需要使用父特徵有非const的訪問。

這是建議的傳承繼傳統的STL模型

class ConstIterator: 
    public std::_Bidit< myType, int, const myType *, const mType & > 
{ 
    reference operator*() const { return m_p; } 
} 

class Iterator : public ConstIterator 
{ 
    typedef ConstIterator _Mybase; 
    // overide the types provided by ConstIterator 
    typedef myType * pointer; 
    typedef myType & reference; 

    reference operator*() const 
    { 
    return ((reference)**(_Mybase *)this); 
    } 
} 

typedef std::reverse_iterator<ConstIterator> ConstReverseIterator; 
typedef std::reverse_iterator<Iterator> ReverseIterator; 
+0

我傾向於將迭代器作爲模板類編寫,並使用類型特徵來操縱成員函數的常量;它避免了'const_cast'的需要,並使得代碼更易於閱讀。 – 2010-10-28 22:22:57

+0

聽起來很有意思,但它是否允許在可能使用const_iterator的地方使用迭代器?我正在對我見過的stl(s)進行這個原始觀察 - 主要針對MSVC。 – 2010-10-28 22:38:56

+0

這實際上是我的用例。我有一個zip迭代器,其中const從非const繼承。 @詹姆斯,你能回答這個問題的類型特徵答案嗎?我真的很感興趣,如果可能的話不要這樣做 – Steve 2010-10-29 01:56:03

0

我發現自己試圖調用這是繼承了一個非const成員函數的快速輪廓,但因爲我是API的實際常量使用。最後,我決定採用不同的解決方案:重新協商API,以便我繼承的功能正常。

協商對其他人的功能所做的更改並不總是可能的,但在可能的情況下這樣做似乎比需要使用const_cast更清潔,更好,並且也會使其他用戶受益。

3

const成員方法的限制來自編譯時。如果你可以愚弄編譯器,那麼是的。

class CFoo 
{ 
public: 
    CFoo() {m_Foo = this;} 
    void tee(); 

    void bar() const 
    { 
     m_Foo->m_val++; // fine 
     m_Foo->tee(); // fine 
    } 
private: 
    CFoo * m_Foo; 
    int m_Val; 

}; 

這實際上取消了const成員函數的目的,所以最好不要在設計一個新類時做。知道有一種方法可以做到這一點並不是什麼壞事,特別是它可以用來解決那些在const member函數的概念上沒有很好設計的舊類。

+0

真是個詭計! ...我會用它:) – Olumide 2016-06-17 11:36:12