3

参照 (ポリモーフィズム) では正しく動作しない単純なコードがあります。

#include <iostream>
#include <string>

class Base {
public:
    Base() {}
    virtual ~Base() {}
    virtual std::string text() const {
        return "Base";
    }
};

class Derived: public Base {
public:
    Derived(Base& _b): b(_b) {}
    virtual ~Derived() {}
    virtual std::string text() const {
        return b.text() + " - Derived";
    }

private:
    Base& b;
};

int main(int argc, char const *argv[])
{
    Base b;
    Derived d1(b);
    std::cout << d1.text() << std::endl;

    Derived d2(d1);
    std::cout << d2.text() << std::endl;
    return 0;
}

そして出力:

Base - Derived
Base - Derived

私が期待した出力の 2 行目: Base - Derived - Derived. 私はいくつかのリソースを読み、ポリモーフィズムは参照とポインターで完全に機能しますが、この状況ではそうではありません。参照をポインターに置き換えると、再び機能します。それで、誰か私に説明をしてもらえますか?

本当にありがとう!

4

4 に答える 4

7

へのデフォルトのコピー コンストラクターを呼び出していますDerived。したがって、終了d2すると の単純なメンバー コピーにd1なり、両方のbメンバーが同じBaseインスタンスを参照します。

これを証明するには、これをDerivedクラスに追加します

class Derived: public Base {
public:
    Derived(Derived& d) : b(d) {}
    Derived(Base& _b): b(_b) {}
    virtual ~Derived() {}
    virtual std::string text() const {
        return b.text() + " - Derived";
    }

private:
    Base& b;
};

これにより、出力は次のようになります。

Base - Derived
Base - Derived - Derived

これは壮大なアイデアでも、ポリモーフィズムの素晴らしい学習例でもないことに注意してください。(しかし、これはコンストラクション オーバーライドの興味深い例です)。また、これはデフォルトのコピー構築 (パラメーターが const-ref-type の場合) の典型的なオーバーライドではないことに注意してください。したがって、これが最大のサンプルではない理由の一部です。

于 2013-08-24T05:46:32.383 に答える
1

あなたd1d2両方にタイプDerivedがあるため、これは正しく機能しています。通常、参照は逆になります。例えば

Base b;
Derived d;
Base &dr = d;

std::cout << b.text() << std::endl;
std::cout << dr.text() << std::endl;

Heretext()は型を介して呼び出されますBaseが、後者は のバージョンを呼び出しますDerived

通常、派生クラスを基本クラスを介して初期化できるようにすることは意味がないことに注意してください。Derived2とはかなり異なる能力や状態を持つタイプを追加するとしますDerived。このコンストラクターは許可します

Derived2 d2;
Derived d1(d2);

これはおそらく非常に悪い考えです。

于 2013-08-24T05:43:28.413 に答える
1

Derived d2(d1)コードをインストルメント化すると、Derived::Derived(Base&) コンストラクターが呼び出されていないことがわかります。これは、d1 引数が、b メンバーを d1 から d2 にコピーするだけの暗黙的なコピー コンストラクターに適しているためです。

期待どおりの動作を確認するために、d1 を明示的に にキャストできます(Base&)d1。そうすると、次のようなコードが得られます (インストルメンテーション付き)。

#include <iostream>
#include <string>

class Base {
public:
    Base() {}
    virtual ~Base() {}
    virtual std::string text() const {
        return "Base";
    }
};

class Derived: public Base {
public:
    Derived(Base& _b): b(_b) {std::cout << "init'ed with: " << _b.text() << std::endl;}
    virtual ~Derived() {}
    virtual std::string text() const {
        return b.text() + " - Derived";
    }

private:
    Base& b;
};

int main(int argc, char const *argv[])
{

    std::cout << "Creating Base" << std::endl;
    Base b;

    std::cout << "Creating d1" << std::endl;
    Derived d1(b);
    std::cout << d1.text() << std::endl;

    std::cout << "Creating d2" << std::endl;
    Derived d2(d1);
    std::cout << d2.text() << std::endl;

    std::cout << "Creating d3" << std::endl;
    Derived d3((Base&)d1);
    std::cout << d3.text() << std::endl;

    return 0;
}

これにより、期待される出力が得られます。

Creating Base
Creating d1
init'ed with: Base
Base - Derived
Creating d2
Base - Derived
Creating d3
init'ed with: Base - Derived
Base - Derived - Derived
于 2013-08-24T05:44:52.450 に答える