Skip to main content
GameDev.net gamedev.net
🔒 Locked

Derived std::string not working with derived std::ostream class

Started by Houdini Dec 2, 2001 at 3:09 PM 9 replies 2.1k views
Original Post
Houdini
Houdini
I have a String class derived from a private std::string class. I do this so I can change the interface naming convention to match my own naming style. My new String class has this function defined:
std::ostream &operator <<(std::ostream &stream, const String &str)
{
     return (stream << str.c_str());
}
 
I have a LogStream class derived from a public std::ostream class. When I try to do this:
logstream << str;
 
I get this error message upon compile: type cast'' : conversion from ''class String *'' to ''const class _STL::basic_string,class _STL::allocator > &'' exists, but is inaccessible If my String class isn''t derived from a private std::string then this line works fine. Why is it trying to use the old std:string''s operator << function and not the new one I have defined for the String class? BTW, on a curious note, if I change the line to:
logstream << '' '' << str;
 
then it works fine. I realize that after the first operator << gets called, it returns a ostream class and not a logstream class, since I haven''t redefined the operator << functions in the new derived stream class, but I can''t see why this makes the code compile fine. Any ideas? - Houdini
Houdini
Oluseyi
Oluseyi
quote:
Original post by Houdini
BTW, on a curious note, if I change the line to:

logstream << '' '' << str;

then it works fine. I realize that after the first operator << gets called, it returns a ostream class and not a logstream class, since I haven''t redefined the operator << functions in the new derived stream class, but I can''t see why this makes the code compile fine.

The insertion/extraction operators are not declared virtual, so inherited classes don''t use them. Time to redefine operator <<.
Houdini
Houdini
quote:
Original post by Oluseyi
The insertion/extraction operators are not declared virtual, so inherited classes don't use them. Time to redefine operator <<.


You are right, but why does it work if the user-defined class isn't derived from std::string? It just doesn't make sense.

Either way, I tried to re-implement the operator << functions using this function:

template
LogStream &operator <<(ITEM item)
{
return ((ostream)*this << item);
}


but I keep getting an error when I use the ios::endl manipulator. I guess I could take out the template function and instead implement every datatype by hand and see if that works.

However, since not deriving the class from a private std::string works fine, I figure there must be a logical reason for it, and hopefully an easier way to handle it than redeclaring every << operator. If I'm not mistaken, fstream, strstream and such don't reimplement them.


- Houdini


Edited by - Houdini on December 2, 2001 7:34:02 PM
Houdini
ECKILLER
ECKILLER
Dony use inhertcance with std::string, use composition instead. e.g. String{std::string _str;};

Then provide your interface.

ECKILLER
ECKILLER
Houdini
Houdini
You know, ECKILLER, you bring up a very good point. I don''t even know why I chose to inherit over composition.

I think I''ll change my code to use an instance of std::string instead.

Still, out of curiosity, does anyone know why my code won''t work when inheriting from std::string?


- Houdini
Houdini
Gorg
Gorg
It does not work because you use private inheritance.

public :

public members of base class stay public in Deriv
protected members of base class stay protected in Deriv
private members of base class stay private in Deriv
subclass of Deriv and friend can access public and protected members of base.
Other code can access public members of base

protected :



public members of base class become protected in Deriv:
protected member stay protected in Deriv:
private member stay private in Deriv:
Only Subclas of Deriv can still use the public and protected member of base

private :

public members of base class become protected:
protected member stay protected:
private member stay private:
Subclas of Deriv cannot use the public and protected member of base




But anyway about composition and inheritance :

You should not derive from std::string because the destructor is not virtual. This might cause you some problem later if your derived string implementation does new or delete.

Edited by - Gorg on December 3, 2001 11:02:45 AM
Shannon Barber
Shannon Barber
Genearlly speaking, you shouldn''t inherit from any of the stl classes. There''s a few cases where you want to, when writing adaptors or functors for instance - but never inherit from a container, they''re not designed for it.

Also, generally, operator overloads are friends to the class in question and defined outside of the class. (You have problems with overloads such as operator<<(ostream, ...) because a method expects it''s class type on the lhs, not the rhs).

Why isn''t logstream an _instance of fstream?

Magmai Kai Holmlor
- Not For Rent
The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Houdini
Houdini
quote:
Original post by ECKILLER
Dony use inhertcance with std::string, use composition instead. e.g. String{std::string _str;};


quote:
Original post by Gorg
You should not derive from std::string because the destructor is not virtual. This might cause you some problem later if your derived string implementation does new or delete.


quote:
Original post by Magmai Kai Holmlor
Genearlly speaking, you shouldn't inherit from any of the stl classes. There's a few cases where you want to, when writing adaptors or functors for instance - but never inherit from a container, they're not designed for it.



Ok, I totally agree with you guys. I'll make my container classes contain an instance of STL's version.

quote:
Original post by Magmai Kai Holmlor Also, Why isn't logstream an _instance of fstream?



Magmai, it's inherited from ostream because I added functionality to the stream specifically for logging. For instance, my logstream class has the option of automatically prefixing messages with line numbers and/or timestamps. It uses debugging levels, similar to the compiler warning level in most compilers. It also has specific functions for prefixing errors with a "WARNING - ", "ERROR - ", or "FATAL ERROR - " string. Um, I think that's it =)


Thanks a lot guys, I'll change my class accordingly, which will also fix my problem!


- Houdini

Edited by - Houdini on December 3, 2001 1:26:27 PM
Houdini
Oluseyi
Oluseyi
quote:
Original post by Houdini
[logstream is] inherited from ostream because I added functionality to the stream specifically for logging.
[functionality description followed]

You could still add that functionality inheriting from ofstream, and as an added bonus use the base class file output abilities. You could go as far as inheriting from fstream so you can also easily read in your log data from file.

Right?
Houdini
Houdini
quote:
Original post by Oluseyi
You could still add that functionality inheriting from ofstream, and as an added bonus use the base class file output abilities. You could go as far as inheriting from fstream so you can also easily read in your log data from file.

Right?



That is very true I could do that. Right now, however, the default streambuf isn't a fstreambuf, but rather a WinDebugStreamBuf class I created that sends the output to the debug window in VC++.

The user can easily change the stream to write to a file by creating a filestream and setting the rdbuf pointer to the new stream he/she created.

However, since portability is a major concern in my code, I realize it may seem contradictory to default the stream to a specific IDE. In the end tho, doesn't really matter, since eventually the default logging stream will be the console window in the game framework.

As far as being able to read in the log file, it's a thought. It obviouly wouldn't do much good with output only streams, such as the WinDebugStream or the game console screen tho. Then again, I could just leave output going to the file, and easily implement a console command that displays the contents of a file. That way I could still view the log file in game by typing "Display log.txt" in the console of the game. Heck, that command will probably be implemented anyways to allow users to view help files, config files, etc, in game.

So many possibilities...


- Houdini

Edited by - Houdini on December 3, 2001 2:05:07 PM
Houdini
Oluseyi
Oluseyi
Actually, there''s no good reason to derive from fstream.

Deriving from ofstream is still a good idea per portability.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.