I'm an inexperienced C++ novice, coding for a hobby.
Class A and Class B encapsulate my data, and they contain all the public getter and setter functions for the data members. There will eventually be a vector of Bs through which I will need to iterate.
Class C is an encapsulation of a log file for the entire application. The class opens a file of fixed name and location in its constructor, and provides a public member function to write to the log. Again, all fine when I create and write to it in main() (but what a trial to understand how to output a time from Windows in the right format - yeesh).
However, I want to be able to write to that log file from within all instances of Class A and Class B. There must be a way to write to the log file from, for example, multiple Class B objects (non-concurrently), without having to pass an fstream object into every instance on construction or using a global.
By my reasoning, this is not a case for inheritance, Class B : public Class C, because I don't want multiple logs. Is this an occasion for an STATIC fstream variable in Class B or <gasp> a global variable?
> However, I want to be able to write to that log file from within all instances of Class A and Class B.
> There must be a way to write to the log file from, for example, multiple Class B objects (non-concurrently),
> without having to pass an fstream object into every instance on construction or using a global.
std::clog is a ready made global object which can be used for logging.
To log to a file, set it to use a filebuf as its stream buffer.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#include <iostream>
#include <fstream>
int main()
{
// redirect std::clog to write to the log file
std::filebuf fbuf ;
fbuf.open( "/tmp/my_logfile.txt", std::ios::out ) ;
constauto old_buf = std::clog.rdbuf( std::addressof(fbuf) ) ;
// rest of the program writes log messages using std::clog for example,
std::clog << "this is a test.\n" << 123456 << '\n' ;
// before we quit, restore the original std::clog buffer
std::clog.rdbuf(old_buf) ;
}
You could use the singleton pattern.
Another option would be to pass a pointer of class C to the classes that are supposed to log.
I'll have to research the singleton pattern. I've seen it before, not sure I completely understand it, but never used it, so I'd have to consider how to implement it for a log file. The question remains how do I pass the singleton to every Class B instance?
I understand the pass-by-pointer approach but wanted to avoid it if I could since this would require changing the signatures of the Class B constructors. However, I can get my head around that one.
std::clog is a ready made global object which can be used for logging.
To log to a file, set it to use a filebuf as its stream buffer.
I understand the code you wrote with a very little digging (http://www.cplusplus.com/reference/iostream/clog/?kw=clog). Do I have this right in that it should work if I encapsulate this in Class C's constructor & destructor, and instantiate a Class C instance from main() to reconfigure the steam. No Class C public write function is required since all log output goes to std::clog directly from within Classes A and B.
> Do I have this right in that it should work if I encapsulate this in Class C's constructor & destructor,
> and instantiate a Class C instance from main() to reconfigure the steam. No Class C public write function
> is required since all log output goes to std::clog directly from within Classes A and B.
string time_stamp()
{
// Get the current time in seconds
const time_t t = time(nullptr);
// Convert current time to a time structure
struct tm tmDest;
int error = localtime_s(&tmDest, &t);
string time_stamp;
if (!error)
{
// Format the time and save it to a C-style buffer
// Couldn't figure how to use std::stringstream as an alternative to strftime()
char buf[26] = { 0 };
strftime(buf, sizeof(buf), "%T", &tmDest);
time_stamp = buf;
}
else
time_stamp = "Time Error"; // Consider throwing an exception here instead.
return time_stamp;
}