C++ の特殊メンバー
定数メンバー
- constデータメンバー
- Const 型変数は変更できず、読み取り専用モードになります。
- 初期化パラメータリストを使用して初期化する必要があります。
- const メンバー関数
- 書き方としては関数の後にconstを書きます。
- 定数メンバー関数はデータ メンバーを変更できず、データ メンバーの読み取りのみが可能です。
- 定数メンバー関数は通常の関数と同時に存在できます
- 通常の関数と定数メンバー関数が同じ場合、通常のオブジェクトは最初に通常の関数を呼び出します。
- 通常のオブジェクトは定数メンバー関数を呼び出すことができます
- const オブジェクト: const によって変更されたオブジェクト
- 定数オブジェクトは定数メンバー関数のみを呼び出すことができます
#include <iostream> #include <string> using namespace std; class MM { public: MM(string name, int num) :num(num) { MM::name = name; //可以用,也可以不用初始化列表 //MM::num = 1001; 必须要用初始化参数列表方式初始化 } void print() { //不能修改 //num = 1001; 错误,只读模式 cout << name << " " << num << endl; } //常成员函数 void print()const { //name = "修改"; 错误,常成员函数不能修改数据 //num = 199; cout << "常成员函数" << endl; } void printData() { cout << "普通函数" << endl; } protected: string name; const int num; //const数据成员 }; int main() { MM mm("对象", 18); mm.print(); //普通对象调用普通函数 const MM cmm("常对象", 20); cmm.print(); //常对象调用常成员函数 //cmm.printData(); //错误!,常对象只能调用普通函数 return 0; }
静的メンバー
静的メンバーはオブジェクトではなくクラスに属します。つまり、すべてのオブジェクトに共通であり、オブジェクトなしでもオブジェクトありでも呼び出すことができます。オブジェクトを使用して呼び出された場合、静的メンバーは引き続きアクセス許可の対象となります。
静的データメンバー
クラスの外で初期化する必要があり、静的な変更は必要ありませんが、クラス名の修飾が必要です
クラスの初期化が間違っているため、初期化パラメータ リスト メソッドを使用して初期化できません。
静的メンバー関数
関数の前に static を書くだけです
非静的メンバーを呼び出すには、オブジェクトを指定する必要があります
静的オブジェクト
リリースは最後にリリースされます
#include <iostream> using namespace std; class MM { public: MM(string name=""):name(name) { num++; } static void printMM(); static void printData(MM& mm) { cout << mm.name <<" "<<num <<endl; } protected: string name; public: static int num; }; //类外初始化,不再需要static修饰,但是需要类名限定 int MM::num = 1; //类外初始化,不再需要static修饰 void MM::printMM() { //调用非静态数据成员,必须要指定对象 //cout << name << endl; 当这个函数不采用对象去调用,name没有来源 //静态调用静态,没什么要求 cout << num << endl; cout << "静态成员函数" << endl; } int main() { //静态数据成员访问,可以不需要对象 cout << MM::num << endl; //什么叫做共有的 MM mm("mm"); //静态数据成员可以通过对象去访问 cout << mm.num << endl; //此时num等于2 MM array[3]; //5 MM* p = new MM("newMM"); //6 cout << MM::num << endl; cout << p->num << endl; cout << mm.num << endl; delete p; p = nullptr; //静态成员函数 MM::printMM(); mm.printMM(); MM::printData(mm); return 0; }
友元
フレンドはフレンドとして記述されます。フレンドは場所を提供するだけで、オブジェクトにクラスを破る許可を与えます (許可は無視します)。
- フレンド機能
- 通常のフレンド機能
- 別のクラスのメンバー関数をフレンド関数として機能させるには、次の順序で使用します。
- カテゴリーB
- クラスA
- クラスAのフレンド関数(クラスBのメンバ関数)
- フレンドクラス
#include <iostream> using namespace std; class MM { friend class GG; public: MM(string name, int age) :name(name), age(age) {} protected: string name; int age; }; class GG { public: void print() { MM mm("mm", 18); cout << mm.name << "\t" << mm.age << endl; } void printMM(MM& mm) { cout << mm.name << "\t" << mm.age << endl; } MM& returnMM(MM& mm) { return mm; } protected: }; //互为友元类的写法 class A { friend class B; public: void printData(); protected: string data="A"; }; class B { public: friend class A; void printData() { A a; cout << a.data << endl; } protected: string data = "B"; }; void A::printData() { B b; cout << b.data << endl; } int main() { MM mm("mm", 18); GG gg; gg.print(); gg.printMM(mm); //cout << gg.returnMM(mm).name << endl; 错误,出了友元类,没有权限 //互为友元 B b; b.printData(); A a; a.printData(); return 0; }
このポインタと明示的な
- 明示的に変更されたコンストラクターが使用されており、暗黙的な変換コンストラクターは許可されません
- このポインタ
- データメンバーと同じ名前を持つ仮パラメータ名を避け、オブジェクトのアドレスを参照してください。
- 関数の戻り値として機能し、オブジェクト自体を返し、*this を使用してオブジェクト自体を表します。
- このポインタは静的メンバー関数では使用できません
#include <iostream> using namespace std; class MM { public: explicit MM(int age) :age(age) {} void print() { cout << age << endl; } protected: int age; }; class GG { public: GG(string name, int age) :name(name), age(age) {} //普通函数不存在初始化参数列表 void initData(string name, int age) { //类名限定 帮助计算机去识别 GG::name = name; this->age = age; } void print() { cout << this->name << " " << this->age << endl; } void printThis() { cout << this << endl; } GG& returnGG() { return *this; } void printGG2(GG& gg) {} static void printStatic() { GG gg("this", 19); cout << gg.name << "\t" << gg.age << endl; } protected: string name; int age; }; int main() { //explicit 不让隐式转换构造 //MM mm = 12; //MM temp = 1.33; MM temp(12); temp.print(); GG gg("长沙吴彦祖", 28); gg.print(); gg.initData("顿开吴彦祖", 38); gg.print(); cout << &gg << endl; gg.printThis(); GG boy("哥哥吴彦祖", 38); cout << &boy << endl; boy.printThis(); gg.returnGG().returnGG().returnGG().returnGG().returnGG().returnGG().print(); GG::printStatic(); return 0; }
ちょっとした運動
作成メソッドを文字列で実装します。
data 関数と c_str 関数を実装して文字列を出力する
文字列リンクを実装するには、append を実装します。
文字列比較を実装する
手書きのデストラクタがメモリを解放する
#include <iostream> #include <cstring> using namespace std; class mystring { public: //mystring() //{ // strSize = 1; // str = new char; // *str='\0'; //}; mystring(const char* str="") { strSize = strlen(str) + 1; mystring::str = new char[strSize]; strcpy_s(mystring::str,strSize,str); } mystring(const mystring& object) { strSize = object.strSize; str = new char[strSize]; strcpy_s(str, strSize, object.str); } char* c_str() { return str; } char* data() { return str; } mystring append(const mystring& object) { //"strcat_s()函数"使用时需要考虑内存空间大小问题,所以创建临时变量来设置大小 mystring temp; //由于两个字符串各有一个"\0",所以-1删去一个"\0" temp.strSize = mystring::strSize + object.strSize-1; temp.str = new char[temp.strSize]; memset(temp.str, 0, temp.strSize); strcat_s(temp.str, temp.strSize, str); strcat_s(temp.str, temp.strSize, object.str); return temp; } int compare(const mystring& object) { return strcmp(str, object.str); } ~mystring() { delete[] str; str = nullptr; } protected: char* str; //需要存储 int strSize; }; int main() { { //1.实现string中创建方式 mystring str1; mystring str2("ILoveyou"); mystring str3(str1); mystring str4 = str2; //2.通过实现data和c_str函数 打印字符串 cout << str2.c_str() << endl; //打印ILoveyou cout << str2.data() << endl; //打印ILoveyou //3.实现append 实现字符串的链接 mystring strOne = "one"; mystring strTwo = "two"; mystring strThree = strOne.append(strTwo); cout << strThree.data() << endl; //onetwo //4.实现字符串比较 cout << strOne.compare(strOne) << endl; //0 } //5.手写析构函数释放内存 return 0; }