2016-01-25 173 views
0

要定義第二個const版本的函數,是否可以安全地執行此操作?它看起來像會有無限遞歸,因爲我想返回const,但我打算調用的另一個函數是非const。可能會導致無限循環?

它適用於g ++,但我擔心這是不安全的。

#include <iostream> 

using namespace std; 

class test { 
public: 
    int* doSomething(int a) { 
     int* someInt = new int(a); 

     return someInt; 
    } 

    const int* doSomething(int a) const { 
     return doSomething(a); 
    } 
}; 

int main() { 
    test a; 

    cout << *a.doSomething(12345) << endl; 

    return 1; 
} 
+3

此代碼調用doSomething'的'非const版本。嘗試調用const版本並觀看它爆炸。 –

+0

爲什麼不在分配它時初始化'someInt':'int * someInt = new int(a);' – erip

+0

我一直認爲C++不允許超載僅返回類型不同的函數.... – Anedar

回答

2

不太:作爲@Pete貝克爾在評論中指出的,如果你曾經被稱爲const版本遞歸:

class test { 
public: 
    int* doSomething(int a) { 
     int* someInt = new int; 
     *someInt = a; 
     return someInt; 
    } 

    const int* doSomething(int a) const { 
     return doSomething(a); 
    } 
}; 

int main() { 
    const test a; 
    // You're not in for a good time: 
    a.doSomething(12345); 
    return 1; 
} 

在提供const和非const版本的函數是需要重複的代碼,最好實施const版本,然後讓非const版本以特定方式調用它。

從斯科特邁爾斯Effective C++ - Third Edition

const和非const成員函數具有基本上相同的實施方式中,代碼重複可以通過使非const版本調用const版本

避免斯科特·邁爾斯繼續提供一個安全的方法來做到這一點:

const int* doSomething(int a) const 
{ 
    int* someInt = new int; 
    *someInt = a; 
    return someInt; 
} 

int* doSomething(int a) 
{ 
    return const_cast<int*>(static_cast<const Test&>(*this).doSomething()); 
} 

在非const版本,有兩種類型轉換:在static_cast基本上變成thisconst this,其中const_cast擅自拋棄的const -ness的回報。這是安全的,因爲要撥打非const版本,您必須擁有非const this

但是,如果你只是提供一個成員訪問,它的簡單和易於閱讀,只是有以下幾點:

class TestAccess; 
class Test 
{ 
    TestAccess& t; 
public: 
    const TestAccess& getA() const { return t; } 
    TestAcess& getA() { return t; } 
}; 
+0

Scott Myers的解決方案非常完美。我試圖想,如果有一種方法可以從'const'的某種方式調用non-'const'版本,我不認爲你可以。謝謝你清楚地解釋這一點。部分問題是我對const方法的工作原理的誤解:http://stackoverflow.com/questions/34983475/why-is-stdbasic-stringoperator-a-const-method-if-its-also-a-non- const-met?answertab = active#tab-top – Zhro

+0

任何需要'const'版本調用非''const'版本的警告?似乎工作正常。 – Zhro

+0

是的:一個'const'成員函數承諾永遠不會改變一個對象的狀態,但是你基本上會調用一個非''constst'函數來改變對象的狀態。非''constst'版本調用'const'版本更安全,因爲非''constst''函數可以爲對象做任何事情。 – Tas

0

在這種情況下,編譯器總是會選擇函數的非const版本,甚至不會調用const函數。 否則編譯器將不會編譯,您正在制動constenss。 比如我修改迅速代碼:

#include <iostream> 

using namespace std; 

class test { 
public: 
    int* doSomething(int a) { 
     int* someInt = new int; 

     *someInt = a; 
     return someInt; 
    } 
    int ax = 10; 
    void somethingElse(int i) 
    { 
     ax = i; 
    } 
    const int* doSomething(int a) const { 
     somethingElse(a); 
     return 0; 
    } 
}; 

int main() { 
    test a; 

    cout << *a.doSomething(12345) << endl; 

    return 1; 
} 

這個例子並不能編譯,因爲你調用一個const範圍內const函數。編譯器不會讓你這樣做。

現在,我知道是一個測試,但通過這種方式,你永遠不會退出遞歸,它將永遠循環,並且在每次調用時都會通過在堆上分配來泄漏內存,這兩件事在一起可能會導致發生災難。

+0

我知道它正在泄漏內存。這只是一個例子。 – Zhro

+0

出於對編碼風格的好奇,是'somethingElse()'縮進8個空格的原因,還是這是一個錯誤? – Zhro

+0

你可以只返回int本身,即使是測試也不明白爲什麼你需要一個泄漏指針。無論如何不是重點。 關於括號,是的錯,我趕緊編碼,並必須在複製粘貼 乾杯 被搞砸 M. –