【问题标题】:virtual insertion operator overloading for base and derived class基类和派生类的虚拟插入运算符重载
【发布时间】:2018-12-01 11:02:12
【问题描述】:
谁能解释一下如何确保派生函数是从基类型的指针调用到派生对象而不是基函数...
另外,虚拟和覆盖关键字是实现此目的的最佳做法吗?
我之前在每个类中用关键字friend定义了每个重载;但是为派生对象的基指针调用了基函数。
int main()
{
// contrived example ...
base* ptr_derived = new derived();
std::cout << *ptr_derived;
delete ptr_derived;
}
class base
{
virtual std::ostream& operator<<(std::ostream output)
{
output << // base details...
return output;
}
};
class derived : public base
{
std::ostream& operator<<(std::ostream output) // override?
{
output << // derived details...
return output;
}
};
【问题讨论】:
标签:
c++
pointers
inheritance
polymorphism
operator-overloading
【解决方案1】:
operator<< 必须是非成员函数,你不能将它们设为virtual。您必须创建另一个virtual 成员函数,并在operator<< 中调用它以使运行时调度工作。例如
class base
{
friend std::ostream& operator<<(std::ostream& output, const base& b)
{
b.print(output);
return output;
}
virtual void print(std::ostream& output) const {
output << // base details...
}
public:
virtual ~base() = default;
};
class derived : public base
{
virtual void print(std::ostream& output) const override {
output << // derived details...
}
};
【解决方案2】:
虚拟函数的工作原理是通过称为 vtable 的指针调用正确的函数。因此,this 的一些偏移量给出了一个指向 vtable 的指针,而 vtable 的一些偏移量给出了该实际对象类型的函数地址。
但是,对于将对象插入流中的operator<< 重载,这将无法(直接)起作用。虚函数必须是成员函数——但是当您重载成员函数时,其 left 操作数必须是您为其提供重载的类型的对象。也就是说,对于重载的成员函数,a << b 被调用为a.operator<<(b);。对于不起作用的流插入,因为左操作数始终是流,而不是您要插入到流中的类型。
要解决这个问题,您必须让运营商本身成为朋友(永远不是会员)。
要获得虚拟行为,您需要调用一个虚拟成员函数:
class base {
public:
virtual std::ostream &write(std::ostream &os) const {
// write myself to the passed stream
return os;
}
friend std::ostream &operator<<(std::ostream &os, base const &b) {
return b.write(os);
}
};
class derived : public base {
public:
std::ostream &write(std::ostream &os) const override {
// write myself to the passed stream
return os;
}
};
现在重载的运算符被调用以获取正确的类型。反过来,它只是为实际传递的对象调用正确的虚函数(base、derived,或者如果您选择创建一个其他派生类)。