web-dev-qa-db-ja.com

暗黙のコピーコンストラクターが基本クラスのコピーコンストラクターを呼び出し、定義されたコピーコンストラクターが呼び出さないのはなぜですか?

Aが基本クラスであり、BAから派生しているクラス階層について考えてみます。

コピーコンストラクターがBで定義されていない場合、コンパイラーはコピーコンストラクターを合成します。このコピーコンストラクターが呼び出されると、基本クラスのコピーコンストラクター(ユーザーから提供されていない場合は合成されたものでも)が呼び出されます。

#include <iostream>

class A {
    int a;
public:
    A() {
        std::cout << "A::Default constructor" << std::endl;
    }

    A(const A& rhs) {
        std::cout << "A::Copy constructor" << std::endl;
    }
};

class B : public A {
    int b;
public:
    B() {
        std::cout << "B::Default constructor" << std::endl;
    }
};

int main(int argc, const char *argv[])
{
    std::cout << "Creating B" << std::endl;
    B b1;
    std::cout << "Creating B by copy" << std::endl;
    B b2(b1);
    return 0;
}

出力:

Creating B
A::Default constructor
B::Default constructor
Creating B by copy
A::Copy constructor

ユーザーがBで独自のコピーコンストラクターを定義した場合、呼び出されると、このコピーコンストラクターは基本クラスのデフォルトコンストラクターを呼び出します。ただし、基本クラスのコピーコンストラクターへの呼び出しが明示的に存在する場合を除きます(たとえば、初期化リスト内)。

#include <iostream>

class A {
    int a;
public:
    A() {
        std::cout << "A::Default constructor" << std::endl;
    }

    A(const A& rhs) {
        std::cout << "A::Copy constructor" << std::endl;
    }
};

class B : public A {
    int b;
public:
    B() {
        std::cout << "B::Default constructor" << std::endl;
    }
    B(const B& rhs) {
        std::cout << "B::Copy constructor" << std::endl;
    }
};

int main(int argc, const char *argv[])
{
    std::cout << "Creating B" << std::endl;
    B b1;
    std::cout << "Creating B by copy" << std::endl;
    B b2(b1);
    return 0;
}

出力:

Creating B
A::Default constructor
B::Default constructor
Creating B by copy
A::Default constructor
B::Copy constructor

私の質問は、ユーザー定義のコピーコンストラクターがデフォルトの動作として基本クラスのコピーコンストラクターを呼び出さないのはなぜですか?

35
Vincenzo Pii

これは、暗黙的なコピーコンストラクターを定義する方法です(デフォルトを呼び出すことは意味がありません)。コンストラクター(コピーまたはその他)を定義するとすぐに、通常の自動動作はデフォルトの親コンストラクターを呼び出すことになるため、特定のユーザー定義コンストラクターのコンストラクターを変更することは一貫性がありません。

7
Mark B

すべての基本子コンストラクターは、親のデフォルトコンストラクターを呼び出します。これが標準の定義方法です。派生クラスBがAのコピーコンストラクターを呼び出すようにしたい場合は、明示的に要求する必要があります。

#include <iostream>

class A {
int a;
public:
A() {
    std::cout << "A::Default constructor" << std::endl;
}

A(const A& rhs) {
    std::cout << "A::Copy constructor" << std::endl;
}
};

class B : public A {
int b;
public:
B() {
    std::cout << "B::Default constructor" << std::endl;
}
B(const B& rhs):A(rhs) {
    std::cout << "B::Copy constructor" << std::endl;
}
};

int main(int argc, const char *argv[])
{
std::cout << "Creating B" << std::endl;
B b1;
std::cout << "Creating B by copy" << std::endl;
B b2(b1);
return 0;
}

これは、コンパイラが親のどのコンストラクタを呼び出すべきかを異なるコンストラクタごとに知ることができないためです。したがって、デフォルトのコンストラクタ他のすべてのコンストラクタについては、明示的に指定する必要があります。

出力:

Creating B
A::Default constructor
B::Default constructor
Creating B by copy
A::Copy constructor
B::Copy constructor
9
Lefteris

単純な(おそらく陳腐な)答えは、あなたがそれを言わなかったからです。派生コピーコンストラクターを作成しているので、その動作を完全に制御できます。ベースへの呼び出しを指定しないと、コンパイラーは、基本クラスのデフォルトコンストラクターを呼び出して基本クラスを初期化するコードを生成します。

2
Lou