27

私は Stack Overflow が初めてで、C++ を独学していますが、まだかなりの初心者です。私が使用している本のかなりの部分を完成させた後 (時代遅れであると見なされたり、優れた本ではないと見なされる可能性があります)、必要な場合にのみ本を参照しながら、いくつかの概念を自分で試してみることで、いくつかの概念を強化することにしましたが、詰まっているように見えます。私が取り組んでいる概念は、継承、ポリモーフィズム、抽象データ型 (ADT)、およびクラスのコードをヘッダー ファイル (.h) と C++ ファイル (.cpp) に分離することです。テキストの壁については事前に申し訳ありませんが、私がどこにいる必要があるかを明確かつ具体的にしたいだけです.

したがって、私の目標は、必要に応じて相互に継承する単純な形状クラスを作成することです。myPoly、myRectangle、myTriangle、mySquare の 4 つのクラスがあります。この概念を正しく理解していれば、myPoly は ADT であるはずです。メソッドの 1 つが純粋な仮想関数 (area メソッド) であるためです。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 を自動的に含める方法があることを確認しました。誰かがそれについての洞察を提供できるなら、それは大歓迎です。また、包含ステートメントで引用符を使用することは、山括弧を使用することとどのように異なるかについても覚えています。以下は、私の小さなプロジェクト用に作成した 9 つのファイルすべてです。コメントのほとんどは、私にとってはちょっとしたメモやリマインダーです。

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;
}

なぜこれらのエラーが発生するのか、またはコード行を受け取ってエラーを解消するのではなく、なぜ私が行ったことが良い/ベスト プラクティスと見なされないのか、非常に興味があります。

4

4 に答える 4

10

インクルージョン ガードは問題ないようです。そうでない場合は、ファイルと行番号の情報を含むコンパイラ エラーが発生する可能性が高くなります。あなたが投稿したエラーは、リンカーエラーのようです。

ただし、コードには「問題」が 1 つあります。原則として、#include.h ファイルのみを使用し、.cpp ファイルは使用しないでください。

解決策に取り掛かります: 私は Code::Blocks に慣れていません。ただし、正しい方向に導くための一般的な情報を提供できることを願っています。過去に使用した一部のコンパイラでは、デフォルトで 1 つの C++ ファイルをコンパイルしてプログラムを実行できました。複数のファイルを含むプログラムをコンパイルするには、プロジェクトを作成する必要がありました。(最近のほとんどのコンパイラでは、最初からプロジェクトを作成する必要があります。) これを念頭に置いて、Code::Blocks でプログラムのプロジェクトを作成する方法を確認することをお勧めします。

于 2012-07-31T20:09:34.460 に答える
5

コードの観点 (少なくとも私が調べたもの) から見ると、かなり良さそうに見えますが、次のようになります。

考慮すべき点が 2 つあります。

  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 はそこからプログラムをビルドしようとするだろうと思います。その 1 つのソース ファイルだけです。ビルドする各プログラムには、関連するすべてのソース ファイルを含める必要があります。

于 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 に答える