C ++:覆盖由另一个方法调用的受保护方法

时间:2012-07-21 13:57:32

标签: c++ inheritance

我有一个关于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()。这只能通过虚拟方法解决吗?

5 个答案:

答案 0 :(得分:8)

是的,您需要使print虚拟,才能使其正常工作。否则,A::foo不知道后代可以提供print的替代实现,愉快地调用A的版本。编译器甚至可以在编译print代码时内联fooA,使B中的实现完全无关。

答案 1 :(得分:4)

为了使派生类重写函数,必须在基类中将该函数声明为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; }
};

答案 2 :(得分:2)

是的,您可以使用虚拟方法使此示例有效,但您也可以使用CRTP

答案 3 :(得分:1)

您的问题的答案,“这只能通过虚拟方法解决吗?”是:不,可以不使用虚方法。

您需要做的就是将foo()方法复制到B的正文。

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

答案 4 :(得分:0)

是的,如果没有虚拟方法或重写void foo()

,则无法解决问题

因为当A正在编译时,它对B一无所知,所以无法调用其方法