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的版本。编译器甚至可以在编译的时候内联print里面的代码,使得实现完全不相关。fooAB

于 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 回答