C++ Inheritance in Separate Files Using #include and Inclusion Guards

别来无恙 提交于 2020-02-26 11:20:37

问题


I am new to Stack Overflow and am teaching myself C++, but am still quite a beginner. After completing a nice chunk of the book I am using (which may be considered out dated and/or not a great book) I decided to re-enforce some concepts by trying them on my own, referencing the book only if needed, but I appear to be stuck. The concepts I am trying to tackle are inheritance, polymorphism, abstract data types (ADT), and separating the code for my classes into header files (.h) and C++ file (.cpp). Sorry in advance for the wall of text, I just want to be clear and specific where I need to be.

So, my goal is to create simple shape classes that inherit from one another where applicable. I have four classes: myPoly, myRectangle, myTriangle, and mySquare. myPoly, if I understood this concept correctly, should be an ADT since one of the methods is a pure virtual function (area method), since creating a myPoly object isn't something I would want a user of my classes to do. myRectangle and myTriangle both derive from myPoly and in turn mySquare derives from myRectangle. I've also included my test program where I planned on testing my classes. I am using Code::Blocks 10.05 and keep getting the following error when I build my test.cpp program:

undefined reference to 'myPoly::myPoly()'

I get 42 similar errors all for the methods of the myPoly class. This happens when I try to build the .cpp files for myRectangle and myTriangle too. With the research I tried to do on the problems I been running into with this little project I feel like something is wrong with my inclusion guards or my #include statements, and something isn't getting included properly or is getting included too many times. At first I was providing the .cpp file for myPoly to myRectangle and myTriangle, but read in a couple of places that including the .h file for myPoly is more efficient and some how automatically include its .cpp. If anyone can provide some insight on that, it would be greatly appreciated. I also remember something about how using quotes in your inclusion statements is different than using the angle brackets. Below are all nine files that I have made for my little project. Most of the comments are little notes or reminders to me.

myPoly.h

//Practice with inheritance, polymorphism, and Abstract Data Types
//header file for Polygon class

#ifndef MYPOLY_H
#define MYPOLY_H

class myPoly
{
    public:
        //constructor
        //const reference pass because the values w and h don't change and reference avoid the time it takes to copy large
        //  objects by value (if there were any)
        myPoly();
        myPoly(const float & w, const float & h);

        //destructor
        virtual ~myPoly();

        //accessors
        float getWidth();
        float getHeight();
        void setWidth(const float & w);
        void setHeight(const float & h);

        virtual float area() = 0;

    private:
        float width, height;
};

#endif

myPoly.cpp

//Practice with inheritance, polymorphism, and Abstract Data Types
//implementation file for myPoly class

#include "myPoly.h"

//constructor
myPoly::myPoly()
{
    setWidth(10);
    setHeight(10);
}

myPoly::myPoly(const float & w, const float & h)
{
    setWidth(w);
    setHeight(h);
}

//destructor
myPoly::~myPoly() {}

//accessors
float myPoly::getWidth() {return width;}
float myPoly::getHeight() {return height;}

void myPoly::setHeight(const float & w) {width = w;}
void myPoly::setWidth(const float & h) {height = h;}

//pure virtual functions have no implementation
//area() is handled in the header file

myRectangle.h

//Practice with inheritance, polymorphism, and Abstract Data Types
//declaration file for myRectangle class

#ifndef MYRECTANGLE_H
#define MYRECTANGLE_H

#include "myPoly.h"

class myRectangle : public myPoly
{
    public:
        //constructor
        myRectangle();
        myRectangle(const float & w, const float & h);

        //destructor
        ~myRectangle();

        //this doesn't need to be virtual since the derived class doesn't override this method
        float area();
};

#endif

myRectangle.cpp

//Practice with inheritance, polymorphism, and Abstract Data Types
//implementaion file for the myRectangle class

//get a vauge compiler/linker error if you have virtual methods that aren't implemented (even if it ends up being just
//  a 'stub' method, aka empty, like the destructor)

#include "myRectangle.h"

myRectangle::myRectangle()
{
    setWidth(10);
    setHeight(10);
}

myRectangle::myRectangle(const float & w, const float & h)
{
    setWidth(w);
    setHeight(h);
}

myRectangle::~myRectangle()
{
}

float myRectangle::area()
{
    return getWidth() * getHeight();
}

myTriangle.h

//Practice with inheritance, polymorphism, and Abstract Data Types
//declaration file for myTriangle class

#ifndef MYTRIANGLE_H
#define MYTRIANGLE_H

#include "myPoly.h"

//imagine the triangle is a right triangle with a width and a height
//  |\
//  | \
//  |  \
//  |___\

class myTriangle : public myPoly
{
    public:
        //constructors
        myTriangle();
        myTriangle(const float & w, const float & h);

        //destructor
        ~myTriangle();

        //since nothing derives from this class it doesn't need to be virtual and in turn neither does the destructor
        float area();
};

#endif

myTriangle.cpp

//Practice with inheritance, polymorphism, and Abstract Data Types
//implementation file for myTriangle class

#include "myTriangle.h"

myTriangle::myTriangle()
{
    setWidth(10);
    setHeight(10);
}

myTriangle::myTriangle(const float & w, const float & h)
{
    setWidth(w);
    setHeight(h);
}

myTriangle::~myTriangle()
{
}

float myTriangle::area()
{
    return getWidth() * getHeight() / 2;
}

mySquare.h

//Practice with inheritance, polymorphism, and Abstract Data Types
//declaration file for mySquare class

#ifndef MYSQUARE_H
#define MYSQUARE_H

#include "myRectangle.cpp"

class mySquare : public myRectangle
{
    public:
        //constructors
        mySquare();
        //explicity call the myRectangle constructor within this implementation to pass w as width and height
        mySquare(const float w);

        //destructor
        ~mySquare();
};

#endif

mySquare.cpp

//Practice with inheritance, polymorphism, and Abstract Data Types
//implementation file for mySquare class

#include "mySquare.h"

mySquare::mySquare()
{
    setWidth(10);
    setHeight(10);
}

mySquare::mySquare(const float w)
{
    myRectangle::myRectangle(w, w);
}

mySquare::~mySquare()
{
}

test.cpp

//Practice with inheritance, polymorphism, and Abstract Data Types
//main class that uses my shape classes and experiments with inheritance, polymorphism, and ADTs

#include "myRectangle.cpp"
//#include "mySquare.cpp"
#include "myTriangle.cpp"

#include <iostream>

int main()
{
    myPoly * shape = new myRectangle(20,20);

    return 0;
}

I am very curious as to why I am getting these errors or why something I did may not be considered good/best practice, as opposed to just receiving a line of code to make my errors go away.


回答1:


Your inclusion guards look fine. If they were not, you would most likely get a compiler error, including file and line number information. The error you posted seems more like a linker error.

However, there is one "problem" with your code. As a general rule, you should only #include .h files and not .cpp files.

Now to get to the solution: I am unfamiliar with Code::Blocks myself. However, I hope I can give some general information that will point you in the right direction. Some compilers I have used in the past by default allowed me to compile a single C++ file and run the program. To compile a program with more than one file, I had to create a project. (Most modern compilers force you to create a project from the start.) With this in mind, I would suggest you check out how to create a project for your program in Code::Blocks.




回答2:


From a code stand point (at least what I looked through), it looks pretty good, but:

There are two things to consider:

  1. Don't directly include cpp files. For example, in mySquare.h, #include "myRectangle.cpp" should be #include "myRectangle.h". You want to be including the interface/declarations provided in the header file that tell the program how to make the class, not just the function definitions.

  2. Second, make sure you're compiling with all your object files. I don't know code blocks, but if you were using g++ or something like that, you'd want to do g++ main.cpp myPoly.cpp mySquare.cpp etc. for all files. An error like this may happen if you forget myPoly.cpp, for example, because no definitions for its functions would be included.




回答3:


Everything looks fine, actually. It is probably just as simple as not including myPoly.obj when you link your program. I am not familiar with Code::Blocks (although I know it's fairly popular) but I assume if you just, for example, click on test.cpp and choose "Run", that Code::Blocks will try to build a program from just that one source file. You'll need to include all the relevant source files in each program that you build.




回答4:


Additionally to what the otehr guys said: You are not doing inheritance right...

When you do

class Poly
{
   Poly();
   ~Poly();
}

class Rect : public Poly()
{
   Rect();
   ~Rect();
}

You need to declare the child's constructor the following way:

Rect::Rect() : Poly()
{

}

The child must only be constructed after the father has finished constructing.



来源:https://stackoverflow.com/questions/11747954/c-inheritance-in-separate-files-using-include-and-inclusion-guards

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!