9

C++での継承に関する非常に基本的な質問があります。

class A
{
public:
  void foo() { print(); }
protected:
  void print() {}
};

class B : public A
{
protected:
  void print() { std::cout << "test" << std:: endl; }
};

今、次のコード

B b;
b.foo();

何も出力しないため、foo()は明らかに新しく定義されたprint()を呼び出しませんでした。これは仮想メソッドを使用することによってのみ解決できますか?

4

5 に答える 5

9

printはい、これを機能させるには仮想化する必要があります。そうでなければ、A::foo子孫がのバージョンprintを喜んで呼び出す代替実装を提供できるとは思いもしません。コンパイラは、コードのコンパイル時に内部をAインライン化することさえあり、実装を完全に無関係にします。printfooAB

于 2012-07-21T13:59:36.070 に答える
5

派生クラスが関数をオーバーライドするには、関数をvirtual基本クラスで宣言する必要があります。つまり、呼び出す関数は、オブジェクトの動的タイプに応じて、関数が呼び出されたときに実行時に選択されます。

各オブジェクトの派生型がコンパイル時にわかっている場合、オーバーライドする代わりに、いわゆる「不思議な繰り返しテンプレートパターン」(CRTP)を使用して、派生型の知識を基本クラスに注入することもできます(これは、これをサポートするテンプレート):

template <typename Derived> class A
{
public:
  void foo() { static_cast<Derived*>(this)->print(); }
};

class B : public A<B>
{
private:
  friend class A<B>; // assuming you don't want to make the function public
  void print() { std::cout << "test" << std:: endl; }
};
于 2012-07-21T14:06:56.357 に答える
2

はい、この例を機能させるための仮想メソッドを使用できますが、CRTPを使用することもできます。

于 2012-07-21T14:01:33.860 に答える
1

あなたの質問に対する答えは、「これは仮想メソッドを使用することによってのみ解決できるのでしょうか?」いいえ、仮想メソッドを使用せずに可能です。

あなたがする必要があるのは、foo()メソッドをの本体にコピーすることだけですB

class B : public A
{
public:
  void foo() { print(); }
protected:
  void print() { std::cout << "test" << std:: endl; }
};

三。

于 2012-07-21T14:20:01.700 に答える
0

はい、仮想メソッドや書き直しなしでは解決できませんvoid foo()

Aコンパイルしているときは何も知らないBので、そのメソッドを呼び出すことができないからです

于 2012-07-21T13:59:56.833 に答える