-2

コードを単純化しすぎて、実際の問題を反映していないことに気付きました。詳しくなくてすみません。私が実際にやろうとしていることは次のとおりです。

オンラインデモ:

#include<iostream>

class A
{
    public:
        A();

        virtual void f()= 0;
        void g();
};

A::A()
{
    g();
}

void A::g()
{
    f();
}

class B : public A
{
    public:
        B() {};
        void f() {};
};

int main()
{
    B b;
    return 0;
}

コンストラクターが呼び出されたときにまだ作成されていない A::fため、プログラムは純粋仮想関数を呼び出すと思います。B

これは正しいですか、どうすればこの問題を解決できますか?

先に単純すぎる問題を出してしまったことをお許しください。

4

6 に答える 6

5

他の多くのエラーを削除した後のコードの作業サンプル。

#include<iostream>

class A 
{
    virtual void f()=0;
    public:
    void g();
};

void A::g() 
{
   f();
}

class B : public A 
{

    void f(){std::cout<<"Inside B::f";}
};

int main() 
{
    B b;
    b.g();
    return 0;
}

出力:

内部 B::f

本当の答え を得るために、実際のコードを投稿してください。


編集:
実際のコードを見せてくれたので(コンパイルエラーがありましたが、修正しました)。私はあなたの問題を理解しています。

Bを使用してクラスのオブジェクトを作成するB b;と、基本クラスのコンストラクタA::A()が呼び出され、次にメソッドが呼び出されますg()g()は基本クラスのメソッドにすぎないため、これにより が呼び出されることに注意してくださいA::g()。これはさらに を呼び出しますf()。今、あなたの期待はこれが呼び出されるはずですB::f()が、そうではありません。

なぜ?
ルールに注意してください。
コンストラクタまたはデストラクタ内では、オブジェクトの型がthis指す型は常に、コンストラクタ/デストラクタが呼び出されている型です。

上記の規則を適用するf()と、 のコンストラクタで呼び出され、 が呼び出され、 がA呼び出さ
this->f()A::f()ますB::f()。さらにA::f()、定義がないため(提供しなかったため)、実行時例外が発生します。

アクティブな例外なしで呼び出された終了と呼ばれる純粋な仮想メソッド。

コンパイラはこれをコンパイル時エラーとして検出できませんでしたvirtual。呼び出される関数は、this静的ではなく何を指しているかに応じて実行時に決定されるためです。コンパイラがこれを検出できる方法はありませんでした。

どうすればこの問題を克服できますか?
コンストラクターで動的ディスパッチを介して行うことはできません。
コンストラクタ/デストラクタを除く他のメソッドから呼び出した場合、期待どおりの動作を実現して期待できます。

コンストラクタとデストラクタで仮想関数を呼び出すことは避けてください。それらは、呼び出す可能性があると思われるバージョンを呼び出さないためです。

于 2011-11-06T13:02:22.263 に答える
0

B::f の関数シグネチャが A::f と一致する場合、A::g で f() を使用すると、必要に応じて B::f を呼び出す必要があります。上記の例では一致し、A::g は B::f を呼び出す必要があります。

実際の関数シグネチャが上記の例よりも複雑な場合は、それらのシグネチャが正確に一致していることを確認してください。そうしないと、コンパイラは B::f を A::f のオーバーライドではなく新しい関数と見なします。

*: 厳密に言えば、戻り値の型は多少異なる可能性がありますが、ここでは関係ないと思います

于 2011-11-06T12:59:00.350 に答える
0

コンパイラ エラーを取り除くと、コードは正常に動作します

于 2011-11-06T13:02:08.680 に答える
0

概念的にはこれでうまくいくはずです。私は長い間 C++ を使用していませんが、これは C# でのこのシナリオとそれほど変わらないはずです。

public class MyBase
{
    public virtual void PrintName() { }
    public void DoWork()
    {
        PrintName();
    }
}

public class MyDerivative : MyBase
{
    public override void PrintName()
    {
        Console.WriteLine("MyDerivative");
    }
}
于 2011-11-06T13:02:38.100 に答える
0
#include <iostream>

class A {
public:
    virtual void f() = 0;
    void g();
};

void A::g() {
    std::cout << "A::g" << std::endl;
    this->f();
}

class B : public A {
public:
    virtual void f();
};

void B::f()
{
    std::cout << "B::f" << std::endl;
}

int main() {
    B b;
    b.g();
    return 0;
}
于 2011-11-06T13:03:18.840 に答える
0

これをソースに追加します:

void B::f()
{
    printf("im B::f\n");
}

あなたのプログラムは動作するはずです。

純粋仮想メソッドがあるため、A のインスタンスを作成することはできません。

于 2011-11-06T13:11:45.527 に答える