プログラム変換セマンティクス
- 私たちが作成したコードの場合、コンパイラーはコードを、コンパイラーが理解して実装しやすいコードに分割します。
- コンパイラがこれらのコードを解析する方法を見てみましょう。
- プログラマーの視点から/コンパイラーの視点から
- プログラマのコードに対する見方とコンパイラのコードに対する見方は常に入れ替わっています。
定義時にオブジェクトを初期化する
class X { public: int m_i; X(const X& tmpx) { m_i = tmpx.m_i; cout << "拷贝构造函数被调用" << endl; } X() { m_i = 0; cout << "构造函数被调用" << endl; } }; int main() { X x0; x0.m_i = 15; X x1 = x0; // 定义的时候初始化,调用拷贝构造函数 X x2(x0); // 定义的时候初始化,调用拷贝构造函数 X x3 = (x0); // 定义的时候初始化,调用拷贝构造函数 }
- 出力結果:
- コンパイラパースペクティブに切り替えます。コンパイラは2つのステップに分割されます(コンパイラパースペクティブ)
- X x3;ステップ1:オブジェクトを定義し、オブジェクトにメモリを割り当てます。コンパイラーの観点からは、この文はXクラスのコンストラクターを呼び出しません
- x3.X :: X(x0);ステップ2:オブジェクトのコピーコンストラクターを直接呼び出す
- 総括する:
- コンパイラは最初にオブジェクトを作成し、次にオブジェクトのコピーコンストラクターを呼び出してコピーします。
パラメータの初期化
class X { public: int m_i; X(const X& tmpx) { m_i = tmpx.m_i; cout << "拷贝构造函数被调用" << endl; } X() { m_i = 0; cout << "构造函数被调用" << endl; } ~X() { cout << "析构函数被调用" << endl; } }; void func(X tmpx) { return; } int main() { X x0; func(x0); return 1; }
- 出力結果
- プログラマーの視点:パラメーターを渡すときは、コピーコンストラクターを呼び出してx0をtmpxにコピーします。関数が実行されると、tmpxは破棄されます。
- 最新のコンパイラーの観点から、関数は最初にtmpxオブジェクトを作成し、次にオブジェクトのコピーコンストラクターを呼び出してx0をtmpxにコピーします。X tmpx(x0)の実行プロセスに似ています。
古いコンパイラの視点
- X tmpobj;コンパイラーは一時オブジェクトを生成します
- tmpobj.X :: X(x0);コピーコンストラクターを呼び出す
void func(X tmpx) { return; } 老编译器看func(老编译器角度) void func(X &tmpx) { return; }
- func(tmpobj);一時オブジェクトでfuncを呼び出す
- tmpobj.X ::〜X(); func()が呼び出された後、デストラクタが呼び出されます
- 概要:古いコンパイラーは最初に一時オブジェクトを外部で作成し、次にそれを参照によって関数に渡します(値の受け渡し方法を参照に変更します)。
戻り値の初期化
class X { public: int m_i; X(const X& tmpx) { m_i = tmpx.m_i; cout << "拷贝构造函数被调用" << endl; } X() { m_i = 0; cout << "构造函数被调用" << endl; } ~X() { cout << "析构函数被调用" << endl; } }; X func() { X x0; //.... return x0; } int main() { X my = func(); return 1; }
- 出力結果(プログラマーの観点からの分析):
- 上記のコードに対するコンパイラーの理解(コンパイラーの観点)
- X my;オブジェクトmyを生成するだけで、Xのコンストラクターを呼び出さない
- func(my);
- コンパイラーの観点からのFunc
void func(X &extra) { X x0; //从编译器角度,这里不调用X的构造函数 //... //... extra.X::X(x0); //调用拷贝构造函数,将x0拷贝给外部传来的引用 return; }
クラスにメンバー関数を追加する
class X { public: int m_i; X(const X& tmpx) { m_i = tmpx.m_i; cout << "拷贝构造函数被调用" << endl; } X() { m_i = 0; cout << "构造函数被调用" << endl; } ~X() { cout << "析构函数被调用" << endl; } void functest() { cout << "functest()被调用" << endl; } }; X func() { X x0; //.... return x0; } int main() { func().functest(); return 1; }
- 出力結果:
- プログラマーの視点:
- func()。functest();
- コンパイラーの視点
- X my; Xのコンストラクターを呼び出さない
- (func(my)、my).functest();カンマ式:最初に式1を計算し、次に式2を計算します。コンマ式全体の結果は式2の値です。
- ここで(func(my)は:
void func(X &extra) { X x0; //从编译器角度,这里不调用X的构造函数 //... //... extra.X::X(x0); //调用拷贝构造函数,将x0拷贝给外部传来的引用 return; }