2017年2月20日 星期一

C++ 重載下標符號 const 與非 const 寫兩次整合成一次的辦法

重載operator[]符號

tags: C++ Concept
解決必須重複打兩次的問題

重載下標[]符號

如果一個類別的屬性是帶 const 屬性,那麼他將會呼叫 const 版本的
const Arr a(5);
const int & operator[](size_t idx) const{...}
即便不使用到帶const屬性的類別宣告
仍然有可能在重載運算符號時用上(待確認印象中記得會)
Arr a(5), b(5);
a=a+b;
你就必須寫兩份重載函式
const int & operator[](size_t idx) const{...}
int & operator[](size_t idx){...}
除非確定了,不然還是乖乖補上兩種代碼可能比較省事。
這時候就產生一個問題,代碼可能需要寫兩次,至直接導致修改時要改兩處,麻煩了不少。

參考代碼

/*****************************************************************
Name : 重載下標符號 const 函式
Date : 2017/02/20
By   : CharlotteHonG
Final: 2017/02/20
*****************************************************************/
#include <iostream>
#include <vector>
#include <numeric>

using namespace std;

class Arr{
public:
    // 建構子
    Arr(int len): arr(len){
        iota(arr.begin(),arr.end(),1);
    }
    // 重載下標符號
    int & operator[](size_t idx){
        cout << "**Non_";
        return const_cast<int&>(static_cast<const Arr&>(*this)[idx]);
    }
    const int & operator[](size_t idx) const{
        cout << "**Const**" << endl;
        return arr[idx];
    }
private:
    vector<int> arr;
};

int main(int argc, char const *argv[]){
    // **Const**
    const Arr ca(5);
    cout << ca[0] << endl;
    // **Non-Const**
    Arr a(5);
    cout << a[0] << endl;
    return 0;
}

原理

讓 非const版本 的強制去呼叫 const版本的
static_cast<const class&>(*this)
然後再強制解除 const 屬性
const_cast<typename&>
就可以整合成一份主代碼了

是否可以反過來

實際上也是可以把主代碼寫在非const上,語法的運行是可以的,但這會有一種問題,由const呼叫非const貌似有些奇怪:
都已經限制不能修改了,你還去呼叫可以修改的?
也可以換一個角度想,在強制呼叫非const版本的時候,的這個瞬間所返回的參考所參考之處是可以被修改的,const版本的函式居然會有可能被修改,這不符合const的定義。
為避免這不必要的疑慮,應該由非const版本呼叫const版本,避開這些疑慮
/*****************************************************************
Name : 重載下標符號 const 函式
Date : 2017/02/20
By   : CharlotteHonG
Final: 2017/03/17
*****************************************************************/
#include <iostream>
#include <vector>
#include <numeric>

using namespace std;

class Arr{
public:
    // 建構子
    Arr(int len): arr(len){
        iota(arr.begin(),arr.end(),1);
    }
    // 重載下標符號
    int & operator[](size_t idx){
        cout << "Non";
        // return const_cast<int&>(static_cast<const Arr&>(*this)[idx]);
        return arr[idx];
    }
    const int & operator[](size_t idx) const{
        cout << "Const";
        // return arr[idx];
        return static_cast<const int&>(const_cast<Arr&>(*this)[idx]);
    }
private:
    vector<int> arr;
};

int main(int argc, char const *argv[]){
    // **Const**
    const Arr ca(5);
    cout << " = " << ca[0] << endl;
    // **Non-Const**
    Arr a(5);
    cout << " = " << a[0] << endl;
    return 0;
}

參考

ilikekotomi:參考Scott Meyers的Effective C++ 3rd的第三條款

沒有留言:

張貼留言