Thread: derived class from string

  1. #1
    Registered User brianptodd's Avatar
    Join Date
    Oct 2002
    Posts
    66

    derived class from string

    I am writing a class derived from string for use as a field. All I really want (or need) to overload is the insertion and extraction so that I can read from a data file.

    However, when I am trying to initialize a field, I am getting error messages that say cannot convert from type field to type char *.

    What do I need to do? Do I have to overload the assignment operator(=)?

    Brian
    "In theory, there is no difference between theory and practice. But, in practice, there is."
    - Jan L.A. van de Snepscheut

  2. #2
    Registered User jlou's Avatar
    Join Date
    Jul 2003
    Posts
    1,090
    In addition to posting code, maybe you can reassure us that you've considered the fact that is generally considered a bad idea to use a class that has no virtual destructor (or any other virtual functions) as a base class. In this case, string was not designed to be inherited from through public derivation.

    If you have considered this, then okay, good luck.

    If not, then maybe you should consider a different solution. Or if you are interested maybe I or someone else here can explain the dangers of doing that in more detail.

    ...


    P.S. Yes, I posted this to your question before, but since you never really posted code or answered the question, I thought maybe I'd try again. If all you need to overload from string is the insertion and extraction, I have a feeling there might be an easier, safer, and better way to do it. It really depends on your code and how you are using it.

  3. #3
    Registered User brianptodd's Avatar
    Join Date
    Oct 2002
    Posts
    66
    I'm not sure what the problems would be, this is for a class and I need to write the code this way. I am always into easier and better, but I don't think school operates that way.

    Here is the derived class:

    Code:
    #ifndef FIELD_H
    #define FIELD_H
    
    #include <string>
    #include <iostream>
    #include <fstream>
    
    
    class field : public string
    {
    	public:
    		
    	// CONSTRUCTORS
    	
    	// inherited from string class
    	
    	// MOD MEMBER FUNCTIONS
    	
    	private:
    
    };
    
    ifstream & operator >> (istream & ifs, field & inputField);
    ofstream & operator << (ofstream & ofs, field & outputField);
    
    
    #include "field.h"
    
    ifstream & operator >> (ifstream & ifs, field & inputField)
    {
    	 char temp[150]; 
    	 getline(ifs, temp, '|');
    	 inputField = string(temp);
    	 return is;
    }
    
    ofstream & operator << (ofstream & ofs, field & outputField)
    {
    	while (ofs)
    	{
    		ofs << outputField << '|';
    	}
    }
    This is what I've got. I don't think I need anything else.

    Brian
    "In theory, there is no difference between theory and practice. But, in practice, there is."
    - Jan L.A. van de Snepscheut

  4. #4
    Skunkmeister Stoned_Coder's Avatar
    Join Date
    Aug 2001
    Posts
    2,572
    field should not derive from string. it should have a string as a member instead.then create "passthru" functions for the funcs/ops you need.
    Free the weed!! Class B to class C is not good enough!!
    And the FAQ is here :- http://faq.cprogramming.com/cgi-bin/smartfaq.cgi

  5. #5
    Registered User brianptodd's Avatar
    Join Date
    Oct 2002
    Posts
    66
    I had originally programmed it that way. I had a data member that was a string which I used to pass to functions and stuff. She said that I shouldn't have to do that.

    She said that my class should inherit all the characteristics of the string class. So can you see anything wrong with the code? Other than the fact that this is not the best or easiest way to implement the class.
    "In theory, there is no difference between theory and practice. But, in practice, there is."
    - Jan L.A. van de Snepscheut

  6. #6
    Skunkmeister Stoned_Coder's Avatar
    Join Date
    Aug 2001
    Posts
    2,572
    Anyone who is teaching you to derive from concrete classes is an idiot with no real world experience. Dont learn bad habits. Ask yourself is a field a string or does a field have a string. You should only use public inheritance when a true is-a relationship stands.
    Always favour composition over inheritance when you have a choice.
    Free the weed!! Class B to class C is not good enough!!
    And the FAQ is here :- http://faq.cprogramming.com/cgi-bin/smartfaq.cgi

  7. #7
    Registered User jlou's Avatar
    Join Date
    Jul 2003
    Posts
    1,090
    I can't say that I'm more knowledgable than your instructor, so I won't say that I'm right and she is wrong, but it might not hurt to mention to her that you've been warned not do derive from string since deriving from a class without a virtual destructor can lead to undefined behavior. Of course, this may only be an exercise to show how to derive a class, overload operators, or some other thing, but still, I would think she should mention the dangers involved in doing this.

    By the way, is there any reason you must use the operator<< and operator>> for your insertion and extraction? It seems that a separate function would make more sense. I noticed you used getline() in your code. That is a function that is very similar to what you might want to accomplish. So if you aren't required to use the operators for the assignment, I would suggest creating a function that takes an input stream and a string variable (or a field variable if your instructor requires it). Do the same for an output stream, and you have yourself a nice elegant solution that is just as easy to use as the getline function you are already using in your code.

    And finally, if you really have to do it the way you started, there are a few points I could make about your code. First, you should tell us what problems you are having with it. I noticed compile errors. For example, there are typos - you use ifstream everywhere except for one place where its istream, and you return the variable 'is' instead of 'ifs' in operator>>. Also, I would recommend using istream and ostream instead of ifstream and ofstream, that way, you can use it with cin and cout. Also, It appears that your output operator<< is defined in terms of itself, which would seem to make it go into an infinite loop. And lastly, your field class does not inherit all constructors. It only "inherits" the default constructor, so you cannot create a field with an initial value. This means your field class does not "inherit all the characteristics of the string class".

  8. #8
    Registered User
    Join Date
    May 2003
    Posts
    161
    you've been warned not do derive from string since deriving from a class without a virtual destructor can lead to undefined behavior
    Generally, I agree with this. However, if you are using public inheritance to extend only the functionality of a class (read: your derived class has no data members) then I don't see a problem. This definitely beats having to write proxy functions for every desirable method in the string class.

  9. #9
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    The instructor is not wrong, and there is nothing wrong with inheriting from concrete classes or classes without virtual destructors.

    Do you know when it is a bad idea to use a class that has no virtual destructor?
    If you do, then you know what not to do when you use one.

    Don't believe all the CS101 BS that you read. Don't get me wrong, there are plenty of "good-programming practices" that one should follow. This isn't one of them.

    This whole notion of not inheriting classes unless they contain a virtual destructor and methods comes from bad C++ authors. Every C++ book has a chapter on polymorphism. And eventually they all get to the part where they describe how not having a virtual destructor can cause problems. Then there are those authors that go on to say: "don't worry about having to memorize the complexities of when not having a virtual destructor can cause problems...all you have to do is remember the rule: only use inheritance if the base class has a virtual destructor". Which is the authors dumb-ass attempt at providing the reading something easier to remember.

    Knowing how something can cause problems so you can avoid it is allot better than restricting your use of language features just to avoid that something (that you can't even do in this case since we're talking about extending a concrete class).

    Ahhhh...vented.

    gg

  10. #10
    Registered User jlou's Avatar
    Join Date
    Jul 2003
    Posts
    1,090
    Originally posted by Codeplug
    The instructor is not wrong, and there is nothing wrong with inheriting from concrete classes or classes without virtual destructors.

    Do you know when it is a bad idea to use a class that has no virtual destructor?
    If you do, then you know what not to do when you use one.
    You see that was my point. Until you know when and why you should not derive from a class with no virtual destructor, you should avoid it or find out the answers. If you are an instructor, and you require your students to solve a problem by deriving from string, you should point out why it could possibly be dangerous. This is similar to pointing out that using the operator[] with vectors can lead to undefined behavior if the index is invalid, or telling students to be aware that use of uninitialized variables is undefined.

    The first reason not to do it is because the person(s) who wrote the class with no virtual destructor made design decisions, including the fact that the class should not be inherited from. It is a design choice whether to make the destructor virtual because you are telling potential users of the class, "hey, don't derive from this class, that's not what I made it for." So while its not the end of the world to use a class in a way that it wasn't intended to be used, it is generally considered bad practice.

    Sometimes what is considered bad practice is still a good solution to a specific problem. I doubt there are very many 100% hard and fast rules that should never be broken. So what is the reason not to do it besides bad practice?

    Basically, by deriving from a class with no virtual destructors, you make the potential even greater for undefined behavior in your program. If you or anybody else who uses your code hold a base class pointer (or reference) to an instance of the derived class, and you delete that instance with the base class pointer (or reference), then you have undefined behavior. Here is an example of mine from another thread:
    Originally posted by jlou
    Code:
    #include <iostream>
    #include <vector>
    
    class BaseClass
    {
    public:
        BaseClass() { }
        // Non-virtual destructor
        ~BaseClass()  { std::cout << "In Base Destructor." << std::endl; }
    };
    
    class DerivedClass : public BaseClass
    {
    public:
        DerivedClass() { }
        // Virtual does not matter here.
        virtual ~DerivedClass() { std::cout << "In Derived Destructor." << std::endl; }
    };
    
    typedef std::vector<BaseClass*> BaseClassPtrArray;
    
    void EmptyAndDelete(BaseClassPtrArray& objList);
    
    int main()
    {
        BaseClassPtrArray myObjList;
    
        myObjList.push_back(new DerivedClass);
        myObjList.push_back(new DerivedClass);
    
        EmptyAndDelete(myObjList);
    }
    
    void EmptyAndDelete(BaseClassPtrArray& objList)
    {
        BaseClassPtrArray::iterator iterObjPtr = objList.begin();
        BaseClassPtrArray::iterator iterEnd = objList.end();
        for(; iterObjPtr != iterEnd; ++iterObjPtr)
        {
            BaseClass* pDeadObj = *iterObjPtr;
            delete pDeadObj; // Undefined behavior
        }
        objList.clear();
    }
    On my machine (MSVC++ 6.0 with upgraded Dinkumware libraries), the base class destructor is called and the derived class destructor is not in the default Release build. In the Debug build I get an error. Clearly, if there is anything important happening in the derived destructor, even in my Release configuration that doesn't crash, that code will not be executed.

    I have seen some that have argued that they don't do anything in their derived destructor and that they "know" that a base class pointer to the derived object will never be deleted. I personally don't think that makes it any smarter, but I guess that is for you to decide.
    As I said in the quote, you could argue that you know that nobody will ever perform the steps required to get the undefined behavior. That's fine. Once you know the risks and rewards of a certain way of doing things, I have no problem with you making up your own mind. In this case, I don't think the student knew the risks, and it sounds like the teacher might not have either (or didn't care enough to inform the students).

    Sorry the post was so long. In a nutshell, it is generally a bad idea because it could lead to incorrect code, and more importantly it violates a design decision made by the writers of the original code. If you are ok with that, fine by me. Good luck.

  11. #11
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Originally posted by jlou
    The first reason not to do it is because the person(s) who wrote the class with no virtual destructor made design decisions, including the fact that the class should not be inherited from. It is a design choice whether to make the destructor virtual because you are telling potential users of the class, "hey, don't derive from this class, that's not what I made it for." So while its not the end of the world to use a class in a way that it wasn't intended to be used, it is generally considered bad practice.
    I realize this nonsense is being fed to our programming youth, but that is absolute garbage! Omitting the "virtual" keyword is not a way communicating to users of your class that you never intended it to be inherited. That's what private constructors and object factories are for.

    Good programming practices lead to more maintainable, readable, and robust code. This doesn't contribute to any of those categories. If this is a good programming practice, then never using operator[] on a vector is a good programming practice too (rubish!).

    Even if you do need to delete polymorphicly, and your base class doesn't have a virtual destructor, there is an easy workaround to prevent you or any of your users from stumbling into undefined behaviour.

    gg

  12. #12
    Registered User jlou's Avatar
    Join Date
    Jul 2003
    Posts
    1,090
    I'll admit that I have not done the research myself and I am merely repeating the things that I have read that make sense to me. You might disagree. I am fine with that. However, I am sure that there are a few programmers out there, like me, who are attempting to learn what good programming techniques are, so they can become as good at what they do as possible. Given that, I am trying to help these programmers by giving them information about certain situations, identifying the pros and cons of programming decisions, and warning them of potential pitfalls of those decisions.

    To that end, I still don't think it is wise to inherit from string. The comparison I was making to operator[] from vector was that you don't teach something without warning about the potential problems. And besides, the difference between that and deriving from string, is that it is perfectly acceptable in the general case and common to delete a base class pointer to an instance of a derived object. It is not perfectly acceptable or common to use operator[] with an invalid index.

    Of course, the most important reason, in my opinion, is that string was not designed to be inherited from. Again, you might say that this notion comes from bad C++ authors. I disagree. In fact, I don't consider Bjarne Stroustrup a bad C++ author. In section 20.3 of The C++ Programming Language 3rd Edition he says:

    From The C++ Programming Language 3rd Edition by Bjarne Stroustrup

    Like other standard library types, a basic_string<T> is a concrete type without virtual functions. It can be used as a member when designing more sophisticated text manipulation classes, but it is not intended to be a base for derived classes.
    You can make up your own mind, but in general, I'll follow the advice of the language creator.

  13. #13
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    I am trying to help these programmers by giving them information about certain situations, identifying the pros and cons of programming decisions, and warning them of potential pitfalls of those decisions.
    We're on the same page there.
    From The C++ Programming Language 3rd Edition by Bjarne Stroustrup

    Like other standard library types, a basic_string<T> is a concrete type without virtual functions. It can be used as a member when designing more sophisticated text manipulation classes, but it is not intended to be a base for derived classes.
    Where does this say "don't inherit an object if it wasn't the programmers intention."? I've developed several classes that I never intended to be inherited from, but that doesn't mean they shouldn't be inherited from. Again, that's one of the nice things that private constructors and object factories accomplish.

    And besides, the difference between that and deriving from string, is that it is perfectly acceptable in the general case and common to delete a base class pointer to an instance of a derived object. It is not perfectly acceptable or common to use operator[] with an invalid index.
    You have conveniently qualified one statement and not the other:

    1) Don't use vector<>::operator[] if the bounds on the index can not be guaranteed.
    2) Don't use polymorphic deletion if the super class contains a destructor and the base class destructor is not virtual.

    Not allot of difference between these two statements.

    gg

  14. #14
    Skunkmeister Stoned_Coder's Avatar
    Join Date
    Aug 2001
    Posts
    2,572
    Worth a read
    Part 2
    Then search through some of the 100's of posts on this very subject on comp.lang.c++.moderated and make your own decision on the subject.
    Yes in some cases it is perfectly safe to do what you are doing but that doesnt necessarily make it the best decision to model the problem domain.
    Free the weed!! Class B to class C is not good enough!!
    And the FAQ is here :- http://faq.cprogramming.com/cgi-bin/smartfaq.cgi

  15. #15
    Registered User jlou's Avatar
    Join Date
    Jul 2003
    Posts
    1,090
    Originally posted by Codeplug
    Where does this say "don't inherit an object if it wasn't the programmers intention."?
    First, who said that was the point of the quote? Besides, it is just common sense. If somebody creates something not intended for a specific purpose, in general it is a good idea to not use it for that purpose. How can you argue that it is perfectly legitimate to ignore the intentions of the designer?
    Originally posted by Codeplug
    there is nothing wrong with inheriting from concrete classes
    This is from Stroustrup's Advice section 25.9:
    From The C++ Programming Language 3rd Edition by Bjarne Stroustrup
    [5] Don't derive from a concrete class
    Again, you can choose your own course of action, but you have to admit that at least one - and I am sure there are many others - important C++ figure disagrees with you. True, that is only a small part of the overall issue, but I'm having trouble finding your point other than to rant against illogical use of "good-programming practices".

    ----

    As somewhat of an aside, you mentioned earlier about "an easy workaround to prevent you or any of your users from stumbling into undefined behaviour". Maybe you could provide that for us. It sounds like the original poster is being forced to do this whether he thinks it is a good idea or not, so it couldn't hurt to give him this extra information.

    In fact, I use a class derived from basic_string here at my work. While I didn't write the class, and I probably would have done it differently if I were to have written that code with my current knowledge, I don't find it necessary to lobby for overhauling our code to remove this "bad design". So an easy workaround to prevent the undefined behaviour might even be of specific use to me. So please share it.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Inheritance Hierarchy for a Package class
    By twickre in forum C++ Programming
    Replies: 7
    Last Post: 12-08-2007, 04:13 PM
  2. Replies: 4
    Last Post: 03-03-2006, 02:11 AM
  3. Linked List Help
    By CJ7Mudrover in forum C Programming
    Replies: 9
    Last Post: 03-10-2004, 10:33 PM
  4. Headers that use each other
    By nickname_changed in forum C++ Programming
    Replies: 7
    Last Post: 10-03-2003, 04:25 AM
  5. creating class, and linking files
    By JCK in forum C++ Programming
    Replies: 12
    Last Post: 12-08-2002, 02:45 PM