27

我是 Stack Overflow 的新手,正在自学 C++,但仍然是个初学者。在完成了我正在使用的书的大部分内容(可能被认为过时和/或不是一本好书)后,我决定通过自己尝试来重新强化一些概念,仅在需要时参考这本书,但我似乎被卡住了。我试图解决的概念是继承、多态性、抽象数据类型 (ADT),以及将我的类的代码分成头文件 (.h) 和 C++ 文件 (.cpp)。提前为文字墙道歉,我只想清楚具体地说明我需要在哪里。

所以,我的目标是创建简单的形状类,在适用的情况下相互继承。我有四个类:myPoly、myRectangle、myTriangle 和 mySquare。如果我正确理解了这个概念,myPoly 应该是 ADT,因为其中一种方法是纯虚函数(区域方法),因为创建 myPoly 对象并不是我希望我的类的用户做的事情。myRectangle 和 myTriangle 都派生自 myPoly,而 mySquare 又派生自 myRectangle。我还包括我计划测试我的课程的测试程序。我正在使用 Code::Blocks 10.05 并在构建我的 test.cpp 程序时不断收到以下错误:

undefined reference to 'myPoly::myPoly()'

对于 myPoly 类的方法,我得到了 42 个类似的错误。当我尝试为 myRectangle 和 myTriangle 构建 .cpp 文件时,就会发生这种情况。通过对我在这个小项目中遇到的问题进行的研究,我觉得我的包含保护或#include 语句有问题,有些东西没有被正确包含或被包含太多次。起初,我将 myPoly 的 .cpp 文件提供给 myRectangle 和 myTriangle,但在几个地方读到,包括 myPoly 的 .h 文件更有效,并且有些地方如何自动包含它的 .cpp。如果有人可以对此提供一些见解,将不胜感激。我还记得在包含语句中使用引号与使用尖括号有何不同。以下是我为我的小项目制作的所有九个文件。大多数评论对我来说都是小笔记或提醒。

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

我的矩形.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

我的矩形.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();
}

我的三角形.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

我的三角形.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()
{
}

测试.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;
}

我很好奇为什么会出现这些错误,或者为什么我所做的事情可能不被认为是好的/最佳实践,而不是仅仅收到一行代码来消除我的错误。

4

4 回答 4

10

你的包容性守卫看起来不错。如果不是,您很可能会收到编译器错误,包括文件和行号信息。您发布的错误似乎更像是链接器错误。

但是,您的代码存在一个“问题”。作为一般规则,您应该只使用#include.h 文件而不是 .cpp 文件。

现在找到解决方案:我自己不熟悉 Code::Blocks。但是,我希望我能提供一些一般信息,为您指明正确的方向。我过去使用的一些编译器默认允许我编译单个 C++ 文件并运行程序。要编译一个包含多个文件的程序,我必须创建一个项目。(大多数现代编译器迫使您从一开始就创建一个项目。)考虑到这一点,我建议您查看如何在 Code::Blocks 中为您的程序创建一个项目。

于 2012-07-31T20:09:34.460 回答
5

从代码的角度来看(至少我看过的),它看起来不错,但是:

有两点需要考虑:

  1. 不要直接包含 cpp 文件。例如,在 mySquare.h 中,#include "myRectangle.cpp"应该是#include "myRectangle.h". 您希望包含头文件中提供的接口/声明,告诉程序如何创建类,而不仅仅是函数定义。

  2. 其次,确保您正在使用所有目标文件进行编译。我不知道代码块,但如果你使用 g++ 或类似的东西,你会想要g++ main.cpp myPoly.cpp mySquare.cpp etc.为所有文件做。例如,如果您忘记了 myPoly.cpp,则可能会发生这样的错误,因为不会包含其函数的定义。

于 2012-07-31T20:05:16.353 回答
3

实际上,一切看起来都很好。链接程序时,它可能就像不包括 myPoly.obj 一样简单。我对 Code::Blocks 不熟悉(尽管我知道它相当流行),但我假设如果您只是单击 test.cpp 并选择“运行”,那么 Code::Blocks 将尝试从只是那一个源文件。您需要在您构建的每个程序中包含所有相关的源文件。

于 2012-07-31T19:59:29.370 回答
-2

除了其他人所说的:你没有做正确的继承......

当你这样做

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

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

您需要通过以下方式声明孩子的构造函数:

Rect::Rect() : Poly()
{

}

孩子必须在父亲完成建造后才能建造。

于 2012-07-31T20:35:22.830 回答