Thread: Using a class from a seperate file.

  1. #1
    Registered User
    Join Date
    May 2007
    Posts
    6

    Post Using a class from a seperate file.

    Hello,

    I'm coming over to C++ from various basics and Java. In java we use separate files for each class to keep things neat. From what I've been able to find online it seems most C++ programs tend to keep a large number of classes in one file?

    Also, let's say I would like to continue using one file per class. I currently have two files one is Line.cpp

    Code:
    /**
      A line represented by its slope and y-intercept.
    */
    class Line{
    	private: 
    	double mySlope;       // the slope for this line
    	double myYIntercept;  // the y-intercept for this line
    	;
    	
    	public:
    	Line(double slope, double yIntercept);
    	~Line();
    	double getSlope();
    	double getYIntercept();
    	double calculateY(double xVal);	
    };
    
    Line::Line(double slope, double yIntercept){
    	mySlope = 1.0;
    	myYIntercept = 5.0;
    };
    
    Line::~Line(){
    	//deconstructors do not accept arguments;
    }
    
    double Line::getSlope(){
    	return mySlope;
    };
    
    double Line::getYIntercept(){
    	return myYIntercept;
    };
    
    double Line::calculateY(double xVal){
    	return myYIntercept+(mySlope*xVal);
    };
    And the other is main.cpp

    Code:
    #include <iostream>
    
    
    
    int main (int argc, char * const argv[]) {
        
        std::cout << "Hello, World!\n";
        return 0;
    }

    What do I need to do so that I can declare new Line objects from my main program?


    Thanks much,

    Norehsa

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    You need the class definition visible in each source file that intends to use the class. Rather than copy-and-pasting the definition into each source file, standard practice is to put it into a header file and include that header file in each source file, including the source file that actually implements the class.

    The contents of the header files included in a source file are actually inserted into the source file by the preprocessor when you compile your program. You use header files all of the time -- iostream, fstream, iomanip. User-defined header files, by convention, usually have a .h extension (though I have seen .H, .hh, .hpp, .h++, etc) and are included with double quotes instead of angle brackets.

    Here's an example.

    Code:
    /* name.h */
    
    /* This # stuff is an inclusion guard, to prevent the header file
    from being included multiple times in the same source file. Always
    use inclusion guards, they're very important. */
    #ifndef HEADER_H
    #define HEADER_H
    
    class name {
    private:
        const char *name;
    public:
        name(const char *name = "Anonymous");
        const char *get_name() { return name; }
    };
    
    #endif
    Code:
    /* name.cpp */
    
    #include "name.h"
    
    name::name(const char *name) {
        this->name = name;
    }
    Code:
    /* main.cpp */
    
    #include <iostream>
    #include "name.h"
    
    int main() {
        name joe("Joe"), normal;
        std::cout << "Hello, " << joe.get_name() << ". Hello, " << normal.get_name() << ".\n";
    
        return 0;
    }
    I have not compiled that example, but you get the idea.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> most C++ programs tend to keep a large number of classes in one file?
    No. C++ programs generally put a single class into a pair of files (usually one .h header file and one .cpp source file) as dwks showed. Other source files that use that class #include the header. The project or makefile or command line for compilation will have all the source files listed and compiled, then linked together.

  4. #4
    Registered User
    Join Date
    May 2007
    Posts
    6
    Thanks a lot. That really helped to clarify a number of things for me.

    I do have two more questions however.

    1.) In your header file it seems you have also included the function body for the get_name. I take it that doesn't break any c++ rules or good syntax guidelines?

    2.) When you declare the new name:
    Code:
    name joe("Joe"), normal;
    what is the ",normal" section do? I tried throwing it on to my line declaration but it threw an error. I'm not seeing where in your name class you define anything to work with such a modifier?

    edit:
    Teach me for simply leaving the browser window open to work off of and not refreshing before replying. Thanks for the clarification Daved

  5. #5
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    1.) In your header file it seems you have also included the function body for the get_name. I take it that doesn't break any c++ rules or good syntax guidelines
    I knew you were going to mention that. Curiosity may have killed the cat, but it made a programmer better.

    You can put the code for a method inline inside the class: if you do so, the function automatically becomes inline. This means that where ever the function is called from, the function call is replaced with the code in the function. So only make very trivial functions inline, three lines or less in general.

    Inline functions are slightly faster but less efficient for code size, because the code inside them gets duplicated.

    You can make ordinary function inline, or methods implemented outside of a class, with the inline keyword.
    Code:
    template <typename T>
    inline T square(T x) {
        return x * x;
    }
    
    // or, without templates:
    
    inline double square(double x) {
        return x * x;
    }
    2.) When you declare the new name:
    Code:
    name joe("Joe"), normal;
    what is the ",normal" section do? I tried throwing it on to my line declaration but it threw an error. I'm not seeing where in your name class you define anything to work with such a modifier?
    It creates another instance of the class name called normal. It's like going
    Code:
    int joe(5), normal;
    which is in turn the same as (for ints, I didn't add name(char *), so this wouldn't work for my name class)
    Code:
    int joe = 5, normal;
    It's identical to
    Code:
    name joe("Joe");
    name normal;
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  6. #6
    Its hard... But im here swgh's Avatar
    Join Date
    Apr 2005
    Location
    England
    Posts
    1,688
    One other thing. Inline is a "request" command to the compiler. If it sees the function will not benefit from doing so, it has the right to ignore the request and will not inline the function, dispite you the programmer having asked it too.
    Double Helix STL

  7. #7
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    The compiler has the right to ignore the request no matter what, even if inlining the function would be beneficial.

    Inline functions are a sort of replacement for macros, which is what one would use in C. You can still use macros in C++, but they're type-generic and hard to debug, etc.

    You can find lots of information about inline functions around.

    http://en.wikipedia.org/wiki/Inline_function
    http://www.intap.net/~drw/cpp/cpp07_05.htm
    http://www.cprogramming.com/tutorial/lesson13.html
    http://www.cprogramming.com/tutorial...timespace.html
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  8. #8
    Registered User
    Join Date
    May 2007
    Posts
    6
    From reading what I found on the inline functions it seems that with modern computers it is not as necessary as it once was? I'm thinking I'll hold off on using them until I get a bit more advanced in the language. I do however have another question which relates to the original question, and it doesn't seem to be in my books.

    I have this as my new Line header:
    Code:
    /* Line.h */
    
    #ifndef _LINE_H
    #define _LINE_H
    #include "Point2D.h"
    /**
      A line represented by its slope and y-intercept.
    */
    class Line{
    	private: 
    	double mySlope;       // the slope for this line
    	double myYIntercept;  // the y-intercept for this line
    	;
    	
    	public:
    	Line(double slope, double yIntercept);
    	Line(Point2D p1,Point2D p2);
    	~Line();
    	double getSlope();
    	double getYIntercept();
    	double calculateY(double xVal);	
    };
    
    #endif
    and this is my new main program:

    Code:
    #include <iostream>
    #include "Line.h"
    #include "Point2D.h"
    int main (int argc, char * const argv[]) {
        Line test(3.0, 4.5);
    	Point2D p1();
    	Point2D p2(3.0, 4.5);
    	Line test2(p1, p2);	
    	std::cout << test.getSlope() << "\n";
    	std::cout << test.getYIntercept() << "\n";
    	std::cout << test.calculateY(5.0) << "\n";
        std::cout << "Hello, World!\n";
        return 0;
    }
    It is throwing an error on the "Line test2(p1, p2);" the error is that there is, "no matching function for call to 'Line::Line(Point2D(&)(), Point2D&)' "

    I'm not recieving any errors in my Line.cpp file where I have defined the second constructor (which the problem line uses.) And there aren't any errors thrown from my Point2D class. While I realize that the lack of errors doesn't mean much I can't shake the feeling that there is a problem with how I am passing the objects to the constructor, or how I defined the constructor. Does anyone have an idea?

    (here is the constructor)
    Code:
    //Constructs a line based on two points.
    Line::Line(Point2D p1, Point2D p2){
    	mySlope = (p2.getY() - p1.getY())/(p2.getX() - p1.getX());
    	myYIntercept = p1.getY()-(p1.getX()*mySlope);
    }

    Many Thanks,

    Norehsa

  9. #9
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> Point2D p1();
    When declaring an object without specifying any parameters you cannot put parentheses or the compiler will think you are trying to declare a function. So remove the parentheses there and you should be fine.

    >> I'm thinking I'll hold off on using [inline functions] until I get a bit more advanced in the language.
    Good choice. You are correct to let the optimizer make that decision. I generally use inline functions only for clarity rather than optimization. For example, something simple like getSlope can be defined inline.

  10. #10
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Quote Originally Posted by Norehsa View Post
    From reading what I found on the inline functions it seems that with modern computers it is not as necessary as it once was? I'm thinking I'll hold off on using them until I get a bit more advanced in the language.
    Yes, that's true. I don't use inline functions unless it's a "set" or a "get" method, and that's usually because it's less typing rather than any concern for efficiency. You shouldn't worry about it, unless one tiny function is abysmally slow.

    I do however have another question which relates to the original question, and it doesn't seem to be in my books.

    I have this as my new Line header:
    Code:
    /* Line.h */
    
    #ifndef _LINE_H
    #define _LINE_H
    #include "Point2D.h"
    /**
      A line represented by its slope and y-intercept.
    */
    class Line{
    	private: 
    	double mySlope;       // the slope for this line
    	double myYIntercept;  // the y-intercept for this line
    	;
    	
    	public:
    	Line(double slope, double yIntercept);
    	Line(Point2D p1,Point2D p2);
    	~Line();
    	double getSlope();
    	double getYIntercept();
    	double calculateY(double xVal);	
    };
    
    #endif
    and this is my new main program:

    Code:
    #include <iostream>
    #include "Line.h"
    #include "Point2D.h"
    int main (int argc, char * const argv[]) {
        Line test(3.0, 4.5);
    	Point2D p1();
    	Point2D p2(3.0, 4.5);
    	Line test2(p1, p2);	
    	std::cout << test.getSlope() << "\n";
    	std::cout << test.getYIntercept() << "\n";
    	std::cout << test.calculateY(5.0) << "\n";
        std::cout << "Hello, World!\n";
        return 0;
    }
    It is throwing an error on the "Line test2(p1, p2);" the error is that there is, "no matching function for call to 'Line::Line(Point2D(&)(), Point2D&)' "

    I'm not recieving any errors in my Line.cpp file where I have defined the second constructor (which the problem line uses.) And there aren't any errors thrown from my Point2D class. While I realize that the lack of errors doesn't mean much I can't shake the feeling that there is a problem with how I am passing the objects to the constructor, or how I defined the constructor. Does anyone have an idea?

    (here is the constructor)
    Code:
    //Constructs a line based on two points.
    Line::Line(Point2D p1, Point2D p2){
    	mySlope = (p2.getY() - p1.getY())/(p2.getX() - p1.getX());
    	myYIntercept = p1.getY()-(p1.getX()*mySlope);
    }

    Many Thanks,

    Norehsa
    Do you have a Point2D(Point2D &) constructor? Because you don't pass the points by reference, you need one. Alternatively, make your Line constructor
    Code:
    Line::Line(Point2D &p1, Point2D &p2){
    Also, one thing to note: identifiers beginning with and underscore followed by another underscore or an uppercase letter -- like _LINE_H -- are reserved for the implementation and should not be used. I'd use LINE_H if I were you.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  11. #11
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> Do you have a Point2D(Point2D &) constructor? Because you don't pass the points by reference, you need one.

    This is incorrect. That is a copy constructor, which will be generated for you if you don't create it yourself. It is likely that the compiler generated version will be enough for a Point2D class. I would leave the code as is assuming the Point2D class/struct is simple.

  12. #12
    Registered User
    Join Date
    May 2007
    Posts
    6
    Those fixed it up perfectly. I can't believe I missed that about the calling a function instead of the constructor, I just finished reading that chapter.

    Thank you much guys.

  13. #13
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Quote Originally Posted by Daved View Post
    >> Do you have a Point2D(Point2D &) constructor? Because you don't pass the points by reference, you need one.

    This is incorrect. That is a copy constructor, which will be generated for you if you don't create it yourself. It is likely that the compiler generated version will be enough for a Point2D class. I would leave the code as is assuming the Point2D class/struct is simple.
    You're right. I missed this constructor
    Code:
    Line(double slope, double yIntercept);
    and so I thought that the numbers were being converted to Point2Ds, meaning that Point2D had at least one constructor: Point2D(double). In that case the default copy constructor Point2D(Point2D &) would not be created and the OP would have needed to create it him or herself.

    But the point still stands: you need a Point2D(Point2D &) constructor, even if the compiler supplies it for you.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  14. #14
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> In that case the default copy constructor Point2D(Point2D &) would not be created and the OP would have needed to create it him or herself.
    Actually, a compiler generated copy constructor is always created even if another constructor is available. It is the default constructor (callable without arguments) that is no longer generated if you make a user-defined constructor.

    >> But the point still stands: you need a Point2D(Point2D &) constructor, even if the compiler supplies it for you.
    I guess, but putting it that way is confusing. It implies you need to do something other than remember that the compiler is handling it for you.
    Last edited by Daved; 05-24-2007 at 07:14 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Need Help Fixing My C Program. Deals with File I/O
    By Matus in forum C Programming
    Replies: 7
    Last Post: 04-29-2008, 07:51 PM
  2. C++ std routines
    By siavoshkc in forum C++ Programming
    Replies: 33
    Last Post: 07-28-2006, 12:13 AM
  3. archive format
    By Nor in forum A Brief History of Cprogramming.com
    Replies: 0
    Last Post: 08-05-2003, 07:01 PM
  4. System
    By drdroid in forum C++ Programming
    Replies: 3
    Last Post: 06-28-2002, 10:12 PM
  5. simulate Grep command in Unix using C
    By laxmi in forum C Programming
    Replies: 6
    Last Post: 05-10-2002, 04:10 PM