Thread: Custom Template

  1. #1
    Registered User
    Join Date
    Mar 2005
    Posts
    54

    Custom Template

    Hi,

    I'm new to this so I'm going to be direct. I'm having trouble with custom template of a Linked List. I've created a Linked List with a reference from a book but I'm at a lost when I store in objects. How do I get the object's data members when I traverse the list of objects.

    Here is my template code for display.

    Code:
    template<class TYPE>
    struct linkNode
      {
        TYPE data;
        linkNode* next;
      };
    
    template<class TYPE>
    void t_List<TYPE>::display()
      {
        linkNode<TYPE>* current = first;
        while (current != NULL)
        {
          cout << endl << current->data;
          current = current->next;
        }
      }

  2. #2
    The larch
    Join Date
    May 2006
    Posts
    3,573
    The Linked List should know nothing about object's datamembers. For the display() method to work, the object must overload ostream operator <<, otherwise the template won't compile.

    In other words, implementing this operator is one of the requirements for a type that can be stored in this list.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  3. #3
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Actually, the way templates work, it's only a requirement if you actually call display(). You can store objects in the list that do not overload << as long as you don't call display() for that particular list.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  4. #4
    Registered User
    Join Date
    Mar 2005
    Posts
    54
    Is it possible if I can grab the head pointer of the list and craft my own display list instead of using the template, this of course is a more targetive approach? If possible, what do you recommend me to change? The private variable of *first to public? I understand that would ruin the concept of data hiding because I'm quite raw in the operator overloading.

    Code:
    template<class TYPE>
    class t_List
      {
        private:
          linkNode<TYPE>* first;
        public:
          t_List() { first = NULL; }
          void addItem(TYPE d);
          void display();
      };
    
    template<class TYPE>
    void t_List<TYPE>::addItem(TYPE d)
      {
        if(first == NULL)
        {
          linkNode<TYPE>* newLink = new linkNode<TYPE>;
          newLink->data = d;
          newLink->next = first;
          first = newLink;
          first->next = NULL;
        }
        else
        {
          linkNode<TYPE>* current = first;
          while(current->next != NULL)
            current = current->next;
    
          linkNode<TYPE>* prev = current;
          current = new linkNode<TYPE>;
          prev->next = current;
          current->next = NULL;
        }
      }

  5. #5
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Quote Originally Posted by CornedBee View Post
    Actually, the way templates work, it's only a requirement if you actually call display(). You can store objects in the list that do not overload << as long as you don't call display() for that particular list.
    Ah, that I didn't know, thinking that all methods need to be compilable if a templated class is instantiated.

    If possible, what do you recommend me to change? The private variable of *first to public? I understand that would ruin the concept of data hiding because I'm quite raw in the operator overloading.
    Normally, displaying the contents is not the kind of task you'd expect from a List. A list's main task is to hold data.

    The list should provide some means to iterate over its contents, so the user can access the contents of each node and deside what to do with it.

    Supposing the following class:
    Code:
    class MyNumber
    {
        public:
            MyNumber(int n): value(n) {}
            void print() const {std::cout << value << '\n';}
        private:
            int value;
    };
    If you stored those in a std::list, that would give you iterators that you can use to access each MyNumber in the list and call the print method.

    Code:
    //create a std::list with some data
    std::list<MyNumber> myList;
    for (int i = 0; i < 10; ++i) {
        myList.push_back(i);
    }
    
    //Now iterate over the list and print each number
    for (std::list<MyNumber>::iterator it = myList.begin(); it != myList.end(); ++it) {
        it->print();
    }
    Note, that the iterator does not expose the list itself (for example a head pointer). It only lets you move through the list (from begin() to end()) and access each MyNumber that you have stored in it.

    Writing your own iterators is a bit of a black magic (there's a recent thread discussing that), so you might stay with your display() method and overload the stream << operator for MyNumber. This is done like that:

    Code:
    class MyNumber
    {
        public:
            MyNumber(int n): value(n) {}
            friend std::ostream& operator<< (std::ostream& os, const MyNumber& num);
        private:
            int value;
    };
    
    std::ostream& operator<< (std::ostream& os, const MyNumber& num)
    {
        return os << num.value;
    }
    The overload is a free function which is declared to be a friend of MyNumber, so it can access the otherwise private value member. Now MyNumber is "coutable":
    Code:
    MyNumber a(12), b(32);
    std::cout << "First: " << a << ", second: " << b << std::endl;
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  6. #6
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    The overload need not (and thus should not) be a friend if all data it wants to display can be accessed through the public interface of the class.

    I.e. if MyNumber has a method
    Code:
    public: int get_value() const { return value; }
    then there's no need for operator << to be a friend. It can be implemented thusly:
    Code:
    std::ostream & operator <<(std::ostream &os, const MyNumber &num)
    {
      return os << num.get_value();
    }
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  7. #7
    Registered User
    Join Date
    Mar 2005
    Posts
    54
    Thanks for the advice but I'm sorry, I find it this quite hard to swallow. My current work now is to analyze various data storages and std::list is one of them.

    My object classes are derived from an abstract base class.

    My current task was to create a custom template list along with other data structures. I do have accessors in my classes.

    Correct me if I'm wrong, so if I put the operator overloading in my seperate classes, wouldn't that overwrite other random std::cout << statements I placed for testing purposes?

    *EDIT
    or if I specify std::cout << "First: " << a << "\n"; and "a" is an object from MyNumber it will use the overload operator.

    The operator will not be overloaded if I just put std::cout << "Test\n";
    Last edited by DarrenY; 10-13-2007 at 12:31 PM.

  8. #8
    The larch
    Join Date
    May 2006
    Posts
    3,573
    The overload only tells cout how to print your particular type and won't change the way other types are cout'ed.

    This bitshift operator is overloaded for ostream in the first place, and there already are multiple overloads.

    Operator overloading is basically the same thing as function overloading :

    Code:
    #include <iostream>
    
    void foo(double)
    {
        std::cout << "Double\n";
    }
    
    void foo(int)
    {
        std::cout << "Int\n";
    }
    
    int main()
    {
        foo(23); //calls foo(int)
        foo(2.3); //calls foo(double)
    }
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  9. #9
    Registered User
    Join Date
    Mar 2005
    Posts
    54
    So do I put the operator overloading in the base class or on the derived classes?

    *EDIT
    Apparently, it clashed with my other display functions from the same objects, or so I thought.

    Code:
    AsteroidList.o:AsteroidList.cpp:(.text+0x340): first defined here
    gameboard.o: In function `operator<<(std::basic_ostream<char, std::char_traits<char> >&, AsteroidType1)':
    Here's a piece of it but there more than just that.
    Last edited by DarrenY; 10-13-2007 at 08:29 PM.

  10. #10
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Sounds like you implemented a non-inline non-template function in a header file. You mustn't do that. Put all function bodies that are neither inline nor templates in .cpp files.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  11. #11
    Registered User
    Join Date
    Mar 2005
    Posts
    54
    Quote Originally Posted by CornedBee View Post
    Sounds like you implemented a non-inline non-template function in a header file. You mustn't do that. Put all function bodies that are neither inline nor templates in .cpp files.
    But my Base class is an abstract class which is a .h file. Where do you recommend me to put the operator?

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Declare it in the header, implement it in a source file.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Well, actually I'd make the << operator inline. But laserlight's method is the best one for larger functions. Nothing stops you from adding another source file, even if the class it is named after is abstract.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Specialising a member function with a template template parameter
    By the4thamigo_uk in forum C++ Programming
    Replies: 10
    Last Post: 10-12-2007, 04:37 AM
  2. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  3. error: template with C linkage
    By michaels-r in forum C++ Programming
    Replies: 3
    Last Post: 05-17-2006, 08:11 AM
  4. Class Template Trouble
    By pliang in forum C++ Programming
    Replies: 4
    Last Post: 04-21-2005, 04:15 AM
  5. oh me oh my hash maps up the wazoo
    By DarkDays in forum C++ Programming
    Replies: 5
    Last Post: 11-30-2001, 12:54 PM