vector.print()とすると一覧表示されたり、pair+pairで2つの要素を足し算するような機能を追加したい。

継承し別の構造体を作る

あるクラスを継承して構造体を作り、自分のほしい機能を追加する。変数名は変わってしまうが、比較的かんたんに実装できる

#include<iostream>
using namespace std;
struct my_string : std::string{//stringを継承する
    using std::string::string;//stringのコンストラクタを継承
    void print(){
        cout << *this << endl;
    }
};
int main(){
    my_string s = "hello";
    s.print();
    //output
    //hello
}

関数名を変えたくないなら、マクロを設定することでコンパイル時に読み替えてくれるようになる

#defineの位置に注意。構造体の中までかわってしまう。

#include<iostream>
using namespace std;
struct my_string : std::string{
    using std::string::string;
    void print(){
        cout << *this << endl;
    }
};
//ここより下に記述
#define string my_string//stringをmy_stringに変換させる
int main(){
    string s = "hello";
    s.print();
    //output
    //hello
}

同様に名前空間を使って衝突を避ける方法もある。このページの最後に紹介している

template宣言がある場合

引数が1つ

vectorのようにテンプレート宣言が必要な場合は少々書き方が煩雑になる。

テンプレート宣言とは、vectorの内要素に対していちいち設定していたら型の数だけ記述しなくてはならないので、型をTと置くことで記述を簡略にしている。

#include<iostream>
#include<vector>
using namespace std;
template<typename T>//my_vector<int>がint型でなくても使えるようテンプレート宣言する
struct my_vector :std::vector<T>{
    using std::vector<T>::vector;//最後のvectorは<T>をつけない
    void print(){
        for(int i=0;i<this->size();i++){
            cout << (*this)[i] << " ";// thisは宣言された要素のポインタ
        }
        cout << endl;
    }
};
int main(){
    my_vector<int> a = {1,2,3};
    a.print();
    //output
    //1 2 3 
}

引数が2つ

#include<iostream>
using namespace std;
template<typename T,typename U>//2つの場合
struct my_pair :std::pair<T,U>{
    using std::pair<T,U>::pair;
    my_pair<T,U> operator+(const my_pair<T,U> p){
        return my_pair<T,U>(this->first + p.first, this->second + p.second);
    }
    void print(){
        cout << this->first << " " << this->second << endl;
    }
};
int main(){
    my_pair<int,int> a(1,2);
    my_pair<int,int> b(1,2);
    (a+b).print();
    //output
    //2 4
}

構造体でなくクラスを用いる

デフォルトの状態だとmainからメンバへアクセスできなかったり、関数を呼び出せなかったりするのでpublic修飾子をつけて対応する

#include<iostream>
using namespace std;
template<typename T,typename U>
class my_pair :public std::pair<T,U>{//publicをつけないとメンバを読み取れなくなる
    using std::pair<T,U>::pair;
    public://public以下にメソッドを作成
    my_pair<T,U> operator+(const my_pair<T,U> p){
        return my_pair<T,U>(this->first + p.first, this->second + p.second);
    }
    void print(){
        cout << this->first << " " << this->second << endl;
    }
};
int main(){
    my_pair<int,int> a(1,2);
    my_pair<int,int> b(1,2);
    (a+b).print();
    //output
    //2 4
}

同じ型名を名前空間で区別する

structまたはclassをmystdという名前空間内で宣言することでmain関数内で使い分ける。

#include<iostream>
namespace mystd{
    using namespace std;
    struct string : std::string{
        using std::string::string;
        void print(){
            std::cout << *this << std::endl;
        }
    };
}
int main(){
    mystd::string s;
    std::string t;//こっちはprint関数を持たない
    s = "hello";
    s.print();
    //output
    //hello
}

namespace std = mystdと名前空間のエイリアスを設定することですべてをstd::に統一できるが、stdやmystdをusingするとエラーになる。以下のコードはすべて実行できない

#include<iostream>
namespace mystd{
    using namespace std;
    struct string : std::string{
        using std::string::string;
        void print(){
            std::cout << *this << std::endl;
        }
    };
}
using namespace std;
int main(){
    namespace std = mystd;
    string s = "hello";
    s.print();//printがメンバーに見つからないエラー
    cout << s;
}
#include<iostream>
namespace mystd{
    using namespace std;
    struct string : std::string{
        using std::string::string;
        void print(){
            std::cout << *this << std::endl;
        }
    };
}
using namespace mystd;
int main(){
    string s = "hello";//stingが曖昧だというエラー
    s.print();
    cout << s;
}

結局記述量が多くなり、自分で関数やマクロを作ったほうが良いのではと感じた。なにか他にいい方法があったら教えてください