Home Inheriting from a C++ class with no virtual functions
Reply: 3

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#
ecatmur Reply to 2013-02-12 10:50:59Z

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<CLogStream *>(&os)) {
    myLogStream->SetMsgTypeCurrent(msgTypeCurrent);
  } else {
    os << "TYPE: " << static_cast<typename std::underlying_type<eMsgType::type>
      ::type>(msgTypeCurrent) << ": ";
  }
  return os;
}
Bart van Ingen Schenau
3#
Bart van Ingen Schenau Reply to 2013-02-12 11:12:33Z

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.

Pete Becker
4#
Pete Becker Reply to 2013-02-12 13:13:57Z

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.

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.421936 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO