此代码演示了问题:
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
,并且有什么解决方案,这样我就不必没有虚拟方法了?
答案 0 :(得分:0)
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";
}
};