Home Inheriting from a C++ class with no virtual functions

# Inheriting from a C++ class with no virtual functions

Simon Elliott
1#
Simon Elliott Published in 2013-02-12 10:33:31Z
 We have a log implementation that's based on std::ostream with a custom stream buffer. We implement our application's instance of the log class via a Schwarz counter. To avoid coupling our lower level classes to our log implementation, we can pass a reference to a std::ostream. In this way our lower level classes can log to std::cout, std::cerr or to the instance created via the Schwarz counter. I have one problem with this. The log implementation sets its severity via an overload of the stream operator: // Overload the << operator to set the log message severity inline CLogStream& operator << (CLogStream& myLogStream, eMsgType::type msgTypeCurrent) { myLogStream.SetMsgTypeCurrent(msgTypeCurrent); return ( myLogStream ) ; }  This allows us to use the logger like this: CLog::Main << CLog::MSG_FATAL << "Fatal error" << std::endl;  I'd like to create a reference to our app's instance of the log which is locked to a particular severity. That way, I can pass our utility classes two std::ostream references. One of these would be used for normal reporting and the other for error reporting. These could be set to std::cout and std::cerr, or to some kind of object referring to our log object instance. Unfortunately the std::ostream operator << aren't virtual as far as I'm aware, so I'm not sure how to design such an object. Any thoughts?
ecatmur
2#
 iostream has virtual member functions (specifically, ~ios_base) so you can perform a dynamic_cast in the operator<<: inline std::ostream &operator<<(std::ostream &os, eMsgType::type msgTypeCurrent) { if (CLogStream *myLogStream = dynamic_cast(&os)) { myLogStream->SetMsgTypeCurrent(msgTypeCurrent); } else { os << "TYPE: " << static_cast ::type>(msgTypeCurrent) << ": "; } return os; } 
 If the setting of the severity is persistent, such that both tese lines result in a log entry with fatal severity CLog::Main << CLog::MSG_FATAL << "Log entry 1: " << some_data << std::endl; CLog::Main << "Log entry 2: " << some_other_data << std::endl;  then your logging class is already correctly designed to be passed along as a generic ostream&. You just need separate logger instances for the different log-levels that are supported by the utility classes. This is written under the assumption that the logger class has been inherited from ostream to take advantage of the existing operator<< overloads. In that case, the operator<< for some_data and some_other_data are already completely unaware that the output goes to a log stream.
 Read about ios_base::iword(). It gives you access to an array of long values in the stream object that you can use to store things like flags and special values.