など、多くの一般的なデータ構造を事前に定義しています.
c.c++標準ライブラリのcoutとcinの使用方法(コードは以下の通り).#include <cstdio>
#include <iostream>
using namespace std;
int main()
{
int a;
int b;
printf("put a :
");
cin >> a;
printf("put b :
");
cin >> b;
cout << "sum is : " << a+b << endl;
return 0;
}
2.グローバル関数のオペレータの再ロード:
a.c++ではoperatorキーワードで関数拡張オペレータ、すなわちオペレータ再ロードを利用できます.
Operatorの本質は、関数リロードによってオペレータのリロードを実現することであるため、オペレータリロードは関数リロードのルールに従う.
b.c++のクラスの友元の定義:
private宣言により、クラスのメンバーは外部からアクセスできませんが、friendキーワードで友元として権限を開放できます.友元アクセスメンバー変数は、依然としてオブジェクトによってアクセスされ、メンバー関数とは大きく異なり、通常のメンバー関数はメンバー変数に直接アクセスでき、オブジェクトは必要ありません.
コードの例は次のとおりです.#include <iostream>
using namespace std;
class test
{
private:
int a;
int b;
public:
test (int a, int b)
{
this->a = a;
this->b = b;
}
int geta()
{
return a;
}
int getb()
{
return b;
}
/* */
friend test operator+ (test& a1, test& a2); //
};
test operator+ (test& a1, test& a2) //
{
test c(0,0);
c.a = a1.a + a2.a;
c.b = a1.b + a2.b;
return c;
}
int main()
{
test n1(1,2);
test n2(2,3);
test n3(0,0);
cout << "a is : " << n3.geta() <<endl;
cout << "b is : " << n3.getb() <<endl;
n3 = n1 + n2;
cout << "a is : " << n3.geta() <<endl;
cout << "b is : " << n3.getb() <<endl;
return 0;
}
注意:上のコードのn 1+n 2はoperator+(n 1,n 2)に等価です.
3.クラスのメンバー関数のオペレータの再ロード:
a.メンバー関数でオペレータを再ロード:グローバル関数より1つ少ないパラメータ、すなわち左オペランドであり、このクラスのオブジェクトでもある.friendキーを使用する必要はありません.
コードは次のとおりです.#include <iostream>
#include <cstdio>
using namespace std;
class test
{
private:
int a;
int b;
public:
test(int a, int b)
{
this->a = a;
this->b = b;
}
test operator+ (test& n2);
friend test operator+ (test& n1, test& n2);
friend ostream& operator<<(ostream& out , test& n);
};
ostream& operator<<(ostream& out , test& n)
{
out << "a is : " << n.a <<endl;
out << "b is : " << n.b ;
return out;
}
test test::operator+ (test& n2) //
{
test n3(0,0);
n3.a = a + n2.a;
n3.b = b + n2.b;
return n3;
}
test operator+ (test& n1, test& n2) //
{
test n3(0,0);
n3.a = n1.a + n2.a + 2;
n3.b = n1.b + n2.b + 2;
return n3;
}
int main()
{
test n1(2,2);
test n2(3,3);
test n3(0,0);
//n3 = n1 + n2; // n3 = n1 + n2
n3 = n1.operator+(n2); // n3 = n1 + n2;
n3 = operator+ (n1, n2); // n3 = n1 + n2;
cout << n3 <<endl; // << operator<<(cout,n3);
operator<<(cout, n3)<<endl;
cout.operator<< (55); // << ostream
return 0;
}
注:メンバー関数のオペレータの再ロード、
op 1シンボルop 2は、
op1.operatorシンボル(op 2)だからop 1はこのクラスのオブジェクトでなければならない
グローバル関数のオペレータの再ロード、
op 1シンボルop 2は、
operatorシンボル(op 1,op 2)だからop 1とop 2はどんなタイプでもいいです
4.メンバー関数とグローバル関数のオペレータ再ロードの適用状況:
a.
左オペランドがクラスのオブジェクトでない場合は、グローバル関数のオペレータのみで再ロードできます.
b.
左オペランドのクラスを変更できない場合は、前に再ロードした<<記号のようにグローバル関数を使用して再ロードします.ostreamというクラスは変更できないので、グローバル関数のオペレータのみを使用して再ロードできます.
c.
実際には、多数のメンバー関数のオペレータリロードは、グローバル関数のオペレータに置き換えられますが、=代入オペレータ、[]配列演算オペレータ、()関数呼び出しオペレータ、->ポインタオペレータは、メンバー関数のみでリロードできます.(この4つのオペレータはc++コンパイラの特殊な規定でメンバー関数のみを使用してオペレータの再ロードを行うことができます.なぜコンパイルに違反したのかは聞かないでください.)
d.
c++コンパイラは、各クラスにデフォルトの付与オペレータを提供します.デフォルトの付与オペレータは、単純な値のコピーを行うだけです.クラスにポインタメンバー変数(特にnewから出てきたメモリを指すポインタ)がある場合は、付与オペレータを再ロードする必要があります.そうしないと、構造関数のdeleteの場合、同じアドレスdeleteに2回!
コードは次のとおりです.#include <iostream>
using namespace std;
class test
{
private:
int a;
int b;
public:
test(int a, int b)
{
this->a = a;
this->b = b;
}
/* test(const test& n)
{
cout<<"hhhhhhh"<<endl;
}*/
test& operator= (test& n2);
friend ostream& operator<<(ostream& out , test& n);
};
ostream& operator<<(ostream& out , test& n)
{
out << "a is : " << n.a <<endl;
out << "b is : " << n.b ;
return out;
}
test& test::operator= (test& n2)
{
a = n2.a + 10;
b = n2.b + 10;
return *this;
}
/**********************************************************************
, ,
test a = b
= ,
, test a; a = b;
, ,
**********************************************************************/
int main()
{
test a(2,2);
test b = a; //
cout << b;
// test b = test(0,0);
// b = a; // =
test c = test(9,9);
b = c;
cout << b;
return 0;
}
注意:第一に、c++コンパイラはクラスにコピーコンストラクタを提供し、割り当てオペレータのリロード関数を提供します.両方のデフォルト関数の機能は同じで、クラスのメンバー変数を簡単にコピーします.
第2に、しかし2つの関数の間は互いに独立していて、test b=aのようなそれぞれの応用シーンがあります.クラス定義が初期化されると、クラスのコピーコンストラクション関数が呼び出されます.また,関数パラメータがクラスのときvoid fun(test a),関数呼び出しがパラメータ伝達を行うときにコピーコンストラクション関数を呼び出し,実虚パラメータ間の伝達を実現する.b=aの2つのクラスが直接値を割り当てる場合、デフォルト値オペレータリロード関数が呼び出されます.
第三に、この2つのデフォルトで提供される関数は、ユーザーが自分で定義すると、元のc++コンパイラが提供したデフォルト関数が失効します.
5.++オペレータのリロード:
a.
c++では、1つの占有パラメータで前置演算と後置演算を区別し、++演算子のリロードはグローバル関数でもメンバー関数でもあり、コードは以下の通りである.#include <iostream>
using namespace std;
class test
{
private:
int a;
int b;
public:
test(int a, int b)
{
this->a = a;
this->b = b;
}
friend ostream& operator<<(ostream& out , test& n);
friend test operator++ (test& a, int);
friend test& operator++ (test& a);
};
ostream& operator<<(ostream& out , test& n)
{
out << "a is : " << n.a <<endl;
out << "b is : " << n.b ;
return out;
}
test operator++ (test& a, int) //a++
{
test ret = a;
a.a++;
a.b++;
return ret;
}
test& operator++ (test& a) //++a
{
++a.a;
++a.b;
return a;
}
int main()
{
test a(0,0);
test b(9,9);
test c(8,8);
b = a++;
cout << b << endl;
cout << a << endl;
cout << "~~~~~" << endl;
c = ++a;
cout << c << endl;
cout << a << endl;
return 0;
}
注意:operator++(test&a,int)はa++後置演算、operator++(test&a)は++a前置演算
6.&&|||オペレータのリロード:
a.
通常の&&&と|内蔵で短絡ルールが実装されているため、&&と|オペレータをリロードしないでください.ただし、オペレータのリロードは関数のリロードで完了し、操作数は関数パラメータとして伝達され、c++の関数パラメータは評価され、短絡ルールは実現できません.
コードは次のとおりです.#include <cstdlib>
#include <iostream>
using namespace std;
class Test
{
int i;
public:
Test(int i)
{
this->i = i;
}
Test operator+ (const Test& obj)
{
Test ret(0);
cout<<"Test operator+ (const Test& obj)"<<endl;
ret.i = i + obj.i;
return ret;
}
bool operator&& (const Test& obj)
{
cout<<"bool operator&& (const Test& obj)"<<endl;
return i && obj.i;
}
};
int main(int argc, char *argv[])
{
int a1 = 0;
int a2 = 1;
if( a1 && (a1 + a2) )
{
cout<<"Hello"<<endl;
}
Test t1 = 0;
Test t2 = 1;
if( t1 && (t1 + t2) ) // t1 0 t1+t2
{
cout<<"World"<<endl;
}
return 0;
}
注意:通常上のt 1+t 2は短絡されるべきで、実行されるべきではありませんが、t 1+t 2は実質的に関数のパラメータなので、実行され、短絡規則に反しています!!
7.本節のまとめ(いくつかのよく出る問題):
a.
=割り当てオペレータ、[]配列オペレータ、()関数呼び出しオペレータ、->ポインタオペレータの4つのオペレータは、メンバー関数のみでリロードできます.
b.
++オペレータはintパラメータで前置と後置のリロードを行います.
c.
c++の中で&&&&|||オペレータをリロードしないでください