2017年3月21日 星期二

operator=() 進階重載,具2種或多種語意重載

operator=() 進階重載,具2種或多種語意重載

tags: C++ Concept
除了一般重載等號之外,如果你想做不同的操作,比如說你希望在指定單一元素的時候可以用等號做存取
Raw a(4, 4);
假設這是一張4x4總共16格的一維陣列

a[0] = -1;
你可以透過下標的等號直接存取

a.at2d(0, 1) = -1;
也可以透過函式進行二維模式的存取

// 區塊等號賦值
a.blk(2) = a.blk(3);
甚至可以在不影響原本運算子的情況下進型區塊複製
區塊指的是以4個單位為一組計算,全部16個可以分成4組
最左上4個為0,最右下4個為3

// 不影響原本的等號
Raw b(4, 4);
a=b;
仍然是預設複製運算子,複製所有資源

用途

這在某些複雜的運算上,可以很大的程度的減少代碼量與程式設計難度
只不過效能上可能多少有些損耗。

參考代碼:
/*****************************************************************
Name : 
Date : 2017/03/21
By   : CharlotteHonG
Final: 2017/03/21
*****************************************************************/
#include <iostream>
#include <iomanip>
#include <vector>
#include <numeric>
#include <cmath>
#include <typeinfo>
using namespace std;

class Raw {
public:
    Raw(size_t y, size_t x): col(x), img(y*x){
        iota(img.begin(), img.end(), 1);
    }
public: // 運算子
// 重載下標符號
int & operator[](size_t idx){
    return const_cast<int&>(static_cast<const Raw&>(*this)[idx]);
}
const int & operator[](size_t idx) const{
    return img[idx];
}
int & at2d(size_t y, size_t x){
    return const_cast<int&>(
        static_cast<const Raw&>(*this).at2d(y, x));
}
const int & at2d(size_t y, size_t x) const{
    return (*this)[y*col+x];
}
public: // 基礎函式
void info(){
    for(unsigned j = 0; j < img.size()/col; ++j) {
        for(unsigned i = 0; i < col; ++i) {
            cout << setw(3) << img[j*col+i];
        }cout << endl;
    }cout << endl;
}
void get_block(size_t h, size_t w);
private:// 資料成員
    size_t col;
    vector<int> img;
private:
    class Block;
    vector<Block> blk_p;
public:
    Block blk(size_t pos);
};

// 轉介的類別
class Raw::Block{
public:
    #define BlkSize 4 // 區塊大小
    Block(): p(BlkSize){}
    Block(Raw & img, size_t pos): p(BlkSize){
        size_t Sidelen = sqrt(BlkSize);
        // 取得對應位置
        size_t pos_y=((pos/((img.img.size())/img.col/Sidelen))*Sidelen);
        size_t pos_x=((pos%(img.col/Sidelen))*Sidelen);
        // 複製指標
        for(unsigned j=0, c=0; j < Sidelen; ++j)
            for(unsigned i = 0; i < Sidelen; ++i, ++c)
                p[c] = &img.at2d(pos_y+j, pos_x+i);
    }
    // 深層拷貝
    Block & operator=(Block const & rhs){
        cout << "C &" << endl;
        if (this == &rhs)
            return (*this);
        for (unsigned i = 0; i < p.size(); ++i)
            *(p[i]) = *(rhs.p[i]);
        return (*this);
    }
    // 淺層拷貝
    Block & copy(Block const & rhs){
        if (this == &rhs){
            return (*this);
        } else {
            p = rhs.p;
        } return (*this);
    }
    Block & copy(Block && rhs){
        if (this == &rhs){
            return (*this);
        } else {
            p = std::move(rhs.p);
        } return (*this);
    }
    void info(){
        for(auto&& i : p) {
            cout << setw(3) << *i ;
        }cout << endl;
    }
public:
    vector<int*> p;
};
auto Raw::blk(size_t pos)-> Block{
    return Block((*this), pos);
}

void Raw::get_block(size_t h=2, size_t w=2){
    size_t len = (img.size()/col/h) * (col/w);
    // cout << "len=" << len << endl;
    this->blk_p.resize(len);
    // blk_p 預載 len 個區塊
    for (unsigned i = 0; i < len; ++i){
        this->blk_p[i].copy( Block((*this), i) );
        // this->blk_p[i].info();
    }
}

/*==============================================================*/
int main(int argc, char const *argv[]){
    Raw a(4, 4);
    a.info();
    // 一般等號賦值
    a[0] = -1;
    a.at2d(0, 1) = -1;
    a.info();
    // 區塊等號賦值
    a.blk(2) = a.blk(3);
    a.info();
    return 0;
}
/*==============================================================*/

沒有留言:

張貼留言