Thread: what's the big idea here?

  1. #1
    Registered User
    Join Date
    Sep 2004
    Posts
    719

    what's the big idea here?

    linker error: undefine reference to <every single templated function>

    everything's in the same directory...i even have object files for them...


    am i just stupid or what? ..........................(sorry for posting such a long post.......oh yea, i know i have not implemented the destructors, but it says nothing else is defined either so, wtf?)

    main.cpp
    Code:
    #include <iostream>
    #include <stdlib.h>
    
    #include "cbox.h"
    
    using namespace std;
    
    template <typename Number>
    ostream & operator <<(ostream &ostr, const cRectangle2<Number> &srcRect)
    {
        ostr << srcRect.getLength() << "x" << srcRect.getWidth();
    }    
    
    template <typename Number>
    ostream & operator <<(ostream &ostr, const cBox<Number> &srcBox)
    {
        ostr << srcBox.getLength << "x" << getWidth() << "x" << srcBox.getHeight();
    }    
    
    template <typename Number>
    Number volume(const cBox<Number> &srcBox)
    {
        ostr << (length * width * height);
    }    
    
    void dummy()
    {
     cout << "non template functoion" << endl;   
    }    
    
    int main(int argc, char *argv[])
    {
      cout.setf(ios::fixed | ios::showpoint);
      cout.precision(1);
      dummy();
      cBox<double> b(4.0, 5.0, 9.0);
      cout << "Output using b with rectangle and box member functions\n";
      cout << "b is " << b << endl;
      cout << "The length is " << b.getLength() << endl;
      cout << "The width is " << b.getWidth() << endl;
      cout << "The height is " << b.getHeight() << endl;
      cout << "The surface area is " << b.area() << endl;
      cout << "The area of the base is " << b.cRectangle2<double>::area();
      cout << "The volume is " << volume(b) << endl;
      cout << "The total perimeter of all sides is " << b.perimeter() << endl;
      cout << "The perimeter of the base is " << b.cRectangle2<double>::area();
      system("PAUSE");	
      return 0;
    }
    rect2.h
    Code:
    #ifndef cRECT2_H
    #define cRECT2_H
    
    #include <iostream>
    using namespace std;
    
    template <typename Number>
    class cRectangle2
    {
        
        friend ostream & operator <<(ostream &, const cRectangle2<Number> &);
        
        public:
        cRectangle2(void);
        cRectangle2(Number, Number);
        cRectangle2(const cRectangle2<Number> &);
        ~cRectangle2(void);
        
        Number perimeter(void) const;
        Number area(void) const;
        
        cRectangle2<Number> & setWidth(Number);
        cRectangle2<Number> & setLength(Number);
        
        Number getWidth(void) const;
        Number getLength(void) const;
        
        
        private:
        Number length;
        Number width;
        
    };
    
    #endif
    rect2.cpp
    Code:
    #include "rect2.h"
    
    using namespace std;
    
    template <typename Number>
    cRectangle2<Number>::cRectangle2(void)
    {
        length = 1;
        width = 1;    
    }    
    
    template <typename Number>
    cRectangle2<Number>::cRectangle2(Number l, Number w)
    {
        length = l;
        width = w;
    }    
    
    template <typename Number>
    cRectangle2<Number>::cRectangle2(const cRectangle2<Number> &srcRect)
    {
        *this = srcRect;    
    }    
    
    template <typename Number>
    cRectangle2<Number>::~cRectangle2(void)
    {
        //this is pointless   
    }    
    
    template <typename Number>    
    Number cRectangle2<Number>::perimeter(void) const
    {
        return ((length*2)+(width*2));   
    }    
    
    template <typename Number>
    Number cRectangle2<Number>::area(void) const
    {
        return (length * width);   
    }    
    
    template <typename Number>    
    cRectangle2<Number> & cRectangle2<Number>::setWidth(Number w)
    {
        width = w;
        return *this;   
    }    
    
    template <typename Number>
    cRectangle2<Number> & cRectangle2<Number>::setLength(Number l)
    {
        length = l;
        return *this;   
    }
    
    template <typename Number>
    Number cRectangle2<Number>::getWidth(void) const{ return width; }
    template <typename Number>
    Number cRectangle2<Number>::getLength(void) const{return length; }
    cbox.h
    Code:
    #ifndef cBOX_H
    #define cBOX_H
    
    #include "rect2.h"
    
    #include <iostream>
    
    using namespace std;
    
    template <typename Number>
    class cBox: public cRectangle2<Number>
    {
       
        friend ostream & operator<<(ostream &, const cBox<Number> &);
        friend Number volume(const cBox<Number> &);
        
        public:
        cBox(Number = 1.0, Number = 1.0, Number = 1.0);
        cBox(const cBox<Number> &);
        ~cBox(void);
        
        Number perimeter(void) const;
        Number area(void) const;
        cBox<Number> & setHeight(Number);
        Number getHeight(void) const;
        
        
        private:
        Number height;
        
    };
    
    #endif
    cbox.cpp
    Code:
    #include "cbox.h"
    
    template <typename Number>
    cBox<Number>::cBox(Number L, Number W, Number H)
    {
        setLength(L);
        setWidth(W);
        height = H;
    }    
    
    
    template <typename Number>
    cBox<Number>::cBox(const cBox<Number> &srcBox)
    {
        *this = srcBox;
    }    
    
    template <typename Number>    
    cBox<Number>::~cBox(void){ /*this is pointless*/ }
    
    template <typename Number>    
    Number cBox<Number>::perimeter(void) const
    {
        return (cBox::perimeter() + (2 * getWidth()));
    } 
     template <typename Number>
    Number cBox<Number>::area(void) const
    {
        return (cBox::area()*2) + (getHeight() * getWidth() * 2) + (getHeight() * getLength() * 2);   
    }    
    
    template <typename Number>
    cBox<Number> & cBox<Number>::setHeight(Number H)
    {
        height = H;
        return *this;   
    }    
    
    template <typename Number>
    Number cBox<Number>::getHeight(void) const
    {
        return height;   
    }

  2. #2
    Registered User
    Join Date
    Mar 2002
    Posts
    1,595
    The rule that all rules have exceptions probably comes into play. The rule is that all class methods should be defined in a cpp file. The exception is that templated classes need to have all functions defined in the h file, not the cpp file.

    Copy all your function definitions to the h file. Either inline them in the declaration or place them after the closing semicolon of the declaration. Comment out all the code in the cpp file (a single /* and */ should do it, if you're lucky). Recompile and see what happens.

  3. #3
    Registered User
    Join Date
    Aug 2003
    Posts
    1,218
    The definition/declaration/whatever (Dont know which one lol, the one where you add code to the functions ) of functions in template classes needs to be in the same file as the class.

    edit: damn! beaten.

  4. #4
    Registered User Micko's Avatar
    Join Date
    Nov 2003
    Posts
    715
    Read this:

    "Header files

    Even if you create non-inline function definitions, you’ll usually want to put all declarations and definitions for a template into a header file. This may seem to violate the normal header file rule of “Don’t put in anything that allocates storage,” (which prevents multiple definition errors at link time), but template definitions are special. Anything preceded by template<...> means the compiler won’t allocate storage for it at that point, but will instead wait until it’s told to (by a template instantiation), and that somewhere in the compiler and linker there’s a mechanism for removing multiple definitions of an identical template. So you’ll almost always put the entire template declaration and definition in the header file, for ease of use.


    There are times when you may need to place the template definitions in a separate cpp file to satisfy special needs (for example, forcing template instantiations to exist in only a single Windows dll file). Most compilers have some mechanism to allow this; you’ll have to investigate your particular compiler’s documentation to use it.


    Some people feel that putting all of the source code for your implementation in a header file makes it possible for people to steal and modify your code if they buy a library from you. This might be an issue, but it probably depends on the way you look at the problem: Are they buying a product or a service? If it’s a product, then you have to do everything you can to protect it, and probably you don’t want to give source code, just compiled code. But many people see software as a service, and even more than that, a subscription service. The customer wants your expertise, they want you to continue maintaining this piece of reusable code so that they don’t have to – so they can focus on getting their job done. I personally think most customers will treat you as a valuable resource and will not want to jeopardize their relationship with you. As for the few who want to steal rather than buy or do original work, they probably can’t keep up with you anyway."
    I hope that id going to help you!

  5. #5
    Registered User
    Join Date
    Sep 2004
    Posts
    719
    well...everything's in the header file....still no go

  6. #6
    Registered User
    Join Date
    Sep 2004
    Posts
    719
    here's a few error messages i get
    [Linker error] undefined reference to `cBox<double>::cBox(double, double, double)'
    [Linker error] undefined reference to `cRectangle2<double>::getLength() const'
    [Linker error] undefined reference to `cRectangle2<double>::area() const'

    //this one's in main
    [Linker error] undefined reference to `volume(cBox<double> const&)'

  7. #7
    Registered User
    Join Date
    Jun 2004
    Posts
    722
    You get undefined references because in your source code you include .h files that declare templates. Templates definition are determined at compile time. If you declare std::vector<char>, an compiled instance of vector will be created associated with char type. If you declare also std::vector<myclass*> you'll have 2 diferent compiled instantiations of vector, one for chars another for pointers of myclass.
    When you include a .h with template definition the compiler is told that the template class is declared and accepts n-template-arguments. Then when the compiler tries to link it can't find any instance of the std::vector<> class associated with the char or myclass* types, simply because they weren't compiled. They weren't compiled because the template .cpp file alone is devoided of any type, therefore not related with you vector instantiations.
    So you'll have to place you method definitions in the .h file. When the .h is included, that way the compiler notices methods definitions with templates which are compiled. Another way, is at the end of your .h file include the .cpp file. People say it bad pratice, bot honestly is exactly the same as placing method definitions in .h files. the advantage of including the .cpp file, is that when compilers by default suport export jeyword, you'll only have to erase the .cpp include from the .h file, and add export before every template in your .cpp file.

    Every good C++ programmer should know this on the tip of his tongue. This is a very important issue in template programming.

  8. #8
    Registered User
    Join Date
    Mar 2002
    Posts
    1,595
    Are you wedded to the idea of having cBox inherit from rectangle? If so, then inheriting templated classes is out of my league. A couple ideas, though they may be off the wall. Who knows.

    public:
    cBox(Number = 1.0, Number = 1.0, Number = 1.0);

    I don't know if you can assign default parameters like that. You may need to list argument names as well as the argument types so the default has some place to be assigned to.

    You probably need to put the definitions of the friend functions in the respective class header files, too, if you haven't already.

    For some nagging reason, I think you might need to call a constructor for the Rectangle class in the cBox class constructor, else, how will the compiler know how to build upon the Rectangle class to make the cBox class? If this is true, the syntax to do so is unknown to me.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. An idea that's out of my reach of knowledge
    By Akkernight in forum Tech Board
    Replies: 12
    Last Post: 04-08-2009, 09:35 PM
  2. Constant too big error
    By John_ in forum C++ Programming
    Replies: 5
    Last Post: 01-26-2006, 01:45 AM
  3. Big and little endian
    By Cactus_Hugger in forum C Programming
    Replies: 4
    Last Post: 10-12-2005, 07:07 PM
  4. creating big projects
    By devil@work in forum C++ Programming
    Replies: 4
    Last Post: 04-04-2003, 04:17 PM
  5. Big O Notation
    By Drew in forum C++ Programming
    Replies: 1
    Last Post: 09-30-2001, 01:22 AM