我有一个关于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()。这只能通过虚拟方法解决吗?
答案 0 :(得分:8)
是的,您需要使print
虚拟,才能使其正常工作。否则,A::foo
不知道后代可以提供print
的替代实现,愉快地调用A
的版本。编译器甚至可以在编译print
代码时内联foo
内A
,使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
一无所知,所以无法调用其方法