继承和覆盖 C++ 中的 ostream 运算符
Inheriting and overriding ostream operator in C++
我一直在试图找到答案,但似乎没有人遇到与我完全相同的问题。
我正在使用几个派生类。对于其中每个运算符<<的 ostream 运算符应该打印出每个内容的一些共同点,以及每个内容特定的一些内容。 稍后,我想进一步从这些派生类中派生,并且新的派生类需要再次打印出它们之上"世代"中的一些东西。
例如:
基类 .h 文件
class Base
{
int FirstClassNumber;
//The declaration I'm currently working with, that a friend gave me
//I'm pretty sure my problem lies here.
public:
friend ostream& operator << (ostream& os, const Base &base)
{
base << os ;
return os;
}
virtual void operator << (ostream& os) const = 0;
};
基本.cpp文件包括以下行:
void Base::operator << (ostream& os)
{
os << FirstClassNumber;
}
然后我派生:(FirstDerived.h)
class FirstDerived : Public Base
{
int SecondClassNumber;
};
首先派生.cpp:
FirstDerived::operator << (ostream& os)
{
os <<
"The first Number is:
//This is the line that isn't working - someone else gave me this syntax
<< Base::operator<<
<< "The second number is"
<< SecondClassNumber;
}
然后我想派生:
class SecondDerived: Public FirstDerived
{
int ThirdClassNumber;
};
第二.cpp:
FirstDerived::operator << (ostream& os)
{
os <<
FirstDerived::operator<<
<< "The third number is "
<< ThirdClassNumber;
}
我认为问题很可能是程序一开始的声明,或者像Base::operator<<
这样的行。
另一种可能性是我没有在每个继承类的 .h 文件中重新声明它。 我应该吗,如果是,我应该使用什么语法?
有人建议我使用static_cast
方法,但我的教授(写作业的人,因此不会给我们太多帮助)说有更好的方法。 有什么建议吗?
一个简单的技术是:
class Base
{
int FirstClassNumber;
public:
virtual void serialize(ostream& os) const
{
os << FirstClassNumber;
}
};
// Implement the stream operator for the base class.
// All it does is call erialize which is a virtual method that
// will call the most derived version.
ostream& operator << (ostream& os, const Base &base)
{
base.serialize(os);
return os;
}
class FirstDerived:public Base
{
int SecondClassNumber;
public:
// Override serialize to make it call the base version.
// Then output any local data.
virtual void serialize(ostream& os) const
{
Base::serialize(os);
os << SecondClassNumber;
}
};
您不能将运算符< <<左侧的东西不会是类的实例,如果它是一个成员函数,它必须是该类的实例。 要从子级呼叫父级 - 执行static_cast: 我认为这是"最佳"解决方案。或者,给你的类一个命名函数调用 Print(),它把一个 ostream 作为一个参数,并使用它来实现你的运算符<<。这将导致许多 cleaer 代码。os << x;
ostream & operator << ( ostream & os, const Child & c ) {
os << static_cast <const Parent &>( c );
// child stuff here
}
除了@Neil所说的之外,实现虚拟DoStream
方法可能会更好,因此您不需要向上转换:
class Base{
private:
virtual void DoStream(ostream& os){
// general stuff
}
public:
friend ostream& operator<<(ostream& os, Base& b){
b.DoStream(os);
return os;
}
};
class Derived : public Base{
private:
void DoStream(ostream& os){
Base::DoStream(os);
// derived specific stuff
}
};
因此,您只需要实现一次运算符。你也可以让operator<<
非朋友和DoStream
公开,但这可能是个人喜好。
FirstDerived.cpp:
FirstDerived::operator << (ostream& os)
{
os << "The first Number is:"
//This is the line that isn't working - someone else gave me this syntax
<< Base::operator<<
<< "The second number is"
<< SecondClassNumber;
}
您需要通过在函数后面加上括号来调用函数,并提供它期望的参数。 它没有返回值,因此不应位于正在流式传输的内容集中。 总结一下:
os << "The first number is: "; // finish streaming statement with ";"
Base::operator<<(os); // separate statement to call this function...
os << "The second number is " << SecondClassNumber; // start streaming again
若要从基类调用方法,可以使用:
Base::method(/*parameters*/)
但operator<<
是一个免费功能。我看不到static_cast的唯一可能性是将运算符定义为模板,然后像这样显式调用专用化:
template<typename T>
void function(T const &t);
template<>
void function<Base>(Base const &t) {
// own implementation ...
}
template<>
void function<Derived>(Derived const &t) {
function<Base>(t);
// own implementation ...
}
对于运算符<<,这可以以相同的方式完成,只需更改operator<<
的名称function
并添加所需的参数即可。
另一种可能性是使虚拟成员函数:
class Base {
virtual void print(ostream &os) const {
// print self
}
};
在派生类中,这可以调用 Base print 函数:
class Derived {
virtual void print(ostream &os) const {
Base::print(os);
// print self
}
};
然后,仅对Base
类进行operator<<
就足够了,它将多态地调用适当的打印方法。请注意,operator<<
是一个免费函数。
ostream &operator<< (ostream &os, Base const &b) {
b.print(os);
return os;
}
这是对洛基答案的轻微修改。 我没有使用虚拟序列化方法,而是使用虚拟to_string方法。 我认为这可以重用于输出到 ostream 的更多上下文中,这可能会有用。
#include <iostream>
#include <string>
class Base
{
public:
Base();
virtual std::string to_string() const;
protected:
int first_class_number;
friend std::ostream& operator<<(std::ostream& os, const Base &base);
};
Base::Base()
: first_class_number(1)
{
}
std::string Base::to_string() const
{
return "Base: "+std::to_string(first_class_number);
}
class FirstDerived : public Base
{
public:
FirstDerived();
std::string to_string() const;
protected:
int second_class_number;
};
FirstDerived::FirstDerived()
: second_class_number(2)
{
}
std::string FirstDerived::to_string() const
{
return "FirstDerived: "+std::to_string(first_class_number)+" "+ std::to_string(second_class_number);
}
std::ostream& operator << (std::ostream& os, const Base &base)
{
os << base.to_string();
return os;
}
int main(int argc, const char *argv[])
{
std::cout << Base() << std::endl;
std::cout << FirstDerived() << std::endl;
return 0;
}
生产
Base: 1
FirstDerived: 1 2
- ostream 运算符<< 为获取 STL 容器而过载,传递 std::string 会破坏它?
- 重载 ostream << 运算符,指针作为参数,导致输出上的内存地址
- ostream 运算符的编译时重载
- 定义 ostream 运算符<<用于类中定义的 typedef
- ostream 运算符<<错误C++
- 使用向量重载 ostream 运算符
- 为什么在重载的 ostream 运算符中引用 lambda 中的向量会导致错误
- C++以友元身份重载 ostream 运算符会导致错误:变量在此上下文中是私有的
- C++ ostream 运算符<<重载
- 动态数组模板类:ostream&运算符友元函数的问题
- 超载Ostream运算符从文件打印矩阵
- "覆盖"ostream&运算符<<
- C++缩进重载了ostream运算符
- 对C++中的istream和ostream运算符进行双重重载
- 是否可以为算术表达式重载 ostream 运算符
- ostream&运算符<<中的类型转换
- 为序列加载 ostream <<运算符
- 重载 std::ostream& 运算符<< 在派生类中而不static_cast<>
- "null logger" - 带有 ostream 运算符的空类会从优化的代码中编译出来吗?
- 重载 << std::ostream 运算符