考虑以下代码片段:
#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会给我一个编译错误说:
$ 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&amp; username)的名称更改为B :: greetUser(const std :: string&amp; username),那么一切都按预期工作我明白了:
$ ./InheritanceTest
Greetings, User!
Hello from C
这是否意味着不能同时在C ++类层次结构中重载和覆盖方法?为什么会这样?有没有合理的理由说明编译器无法明确地解析两个重载的函数原型,并根据需要覆盖相应的原型?
答案 0 :(得分:2)
作为这个答案的前言,你所做的事情很少是一个好主意,因为这些函数具有不同的语义,不应该有相同的名称。
也就是说,您所遇到的问题是,基类中的函数名称被派生类中的函数名称所覆盖。为了解决这个问题,你需要像这样公开它们:
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
使用哪个版本,因此遵循虚拟功能正确。
答案 1 :(得分:1)
使用:
static_cast<A const*>(this)->saySomething();
您还可以使用指向成员函数的指针:
(this->*(&A::saySomething))();