此代码演示了此问题:
class Base
{
public:
explicit Base(std::function<void()> const& printFunc) :
_printFunc(printFunc)
{
}
void print()
{
_printFunc();
}
private:
std::function<void()> _printFunc{};
private:
virtual void _print() = 0; // If this line is commented out, then
// `Subclass1::_print()` can be called.
};
class Subclass1 : public Base
{
public:
explicit Subclass1() :
Base([this]() { _print(); })
{
}
private:
void _print() /*override*/
{
std::cout << "Subclass1\n";
}
};
class Subclass2 : public Base, public Subclass1
{
public:
using fromLowestSubclass = Base;
public:
explicit Subclass2() :
Base([this]() { _print(); }), Subclass1()
{
}
private:
void _print() /*override*/
{
// Here is the problem:
Subclass1::print(); // or: static_cast<Subclass1*>(this)->print();
std::cout << "Subclass2\n";
}
};
int main()
{
Subclass2 sc2{};
sc2.fromLowestSubclass::print();
return 0;
}
在Subclass2::_print
方法中,应该调用_print
的重写Subclass1
方法,而是Subclass1::print();
语句再次调用当前方法。如果语句virtual void _print() = 0;
被注释掉,则可以防止此问题。
为什么使用虚拟_print
方法阻止我调用重载的虚拟方法Subclass1::_print
以及有什么解决方案,以便我不必没有虚拟方法?
class Base
{
....
private:
virtual void _print() = 0;
}
这意味着:你可以覆盖_print
,但你无法调用它,只有Base
有权调用它。
现在:
class Base
{
public:
void print()
{
_printFunc();
}
这样做,它将_printFunc
称为虚拟函数,它匹配当前对象实例化。它没有计量如何调用print()
。
添加Subclass1::
作为前缀只会更改名称范围,并且不会影响方法的行为方式。它只对名称范围产生影响。
现在,如果虚方法有这样的前缀,那么选择名称范围指示编译器放弃抽象,你需要调用特定的方法。在这种情况下,在不参考虚拟表的情况下调用方法。
双重继承对此问题没有影响。
您可以提供一个帮助方法,您可以从祖先调用它:
class Subclass1 : public Base
{
....
protected:
void sub1_print() // not virtual
{
std::cout << "Subclass1\n";
}
private:
void _print() /*override*/
{
sub1_print();
}
};
class Subclass2 : public Base, public Subclass1
{
....
private:
void _print() /*override*/
{
sub1_print();
std::cout << "Subclass2\n";
}
};