考虑以下代码片段:
#include <iostream>
class A
{
public:
virtual ~A(){}
virtual void saySomething() const
{
std::cout << "Hello from A" << std::endl;
}
};
class B : public A
{
public:
virtual ~B(){}
virtual void saySomething(const std::string& username) const
{
std::cout << "Greetings, " << username << "!" << std::endl;
saySomething();
}
};
class C : public B
{
public:
virtual ~C(){}
void saySomething() const
{
std::cout << "Hello from C" << std::endl;
}
};
int main()
{
C* politeC = new C;
B* politeB = dynamic_cast<B*>(politeC);
politeB->saySomething("User");
return 0;
}
铛会给我一个编译器错误,说:
$ clang inheritanceTest.cpp -o InheritanceTestinheritanceTest.cpp:20:9: error: too few arguments to function call, expected 1,
have 0; did you mean 'A::saySomething'?
saySomething();
^~~~~~~~~~~~
A::saySomething
inheritanceTest.cpp:7:18: note: 'A::saySomething' declared here
virtual void saySomething()
^
1 error generated.
但是,如果我确实说了A::saySomething(),那么在C中对saySomething()的重写将被完全忽略。程序打印输出:
$ ./InheritanceTest
Greetings, User!
Hello from A
奇怪的是,如果我只是将B::saySomething(const std::string&username)的名称更改为B::greetUser(const std::string&username),那么一切都会按预期进行,我得到:
$ ./InheritanceTest
Greetings, User!
Hello from C
这是否意味着不能同时重载和重写C++类层次结构中的方法?为什么会这样呢?有任何逻辑上的原因,为什么编译器无法明确解析两个重载的函数原型(prototype),并在必要时覆盖相应的原型(prototype)?
最佳答案
作为该答案的序言,您所做的很少是个好主意,因为这些函数具有不同的语义,并且不应具有相同的名称。
就是说,您遇到的问题是,基类中的函数名被派生类中的函数名覆盖。为了解决此问题,您需要像这样公开它们:
class B : public A
{
public:
using A::saySomething; //HERE expose the function
virtual void saySomething(const std::string& username) const;
{
//the compiler now knows to look in the base class for this function
saySomething();
}
};
class C : public B
{
public:
using B::saySomething; //and HERE
void saySomething() const;
};
现在,可以使用
saySomething
的所有版本来调用C
实例。此外,将C*
转换为B*
将正确地从C::saySomething
调用B::saySomething
,因为您没有明确告诉B
使用哪个版本,因此它正确地遵循了虚函数。