web-dev-qa-db-ja.com

#includeおよびInclusion Guardsを使用した個別のファイルでのC ++継承

私はStack Overflowの初心者であり、自分でC++を教えていますが、それでもかなり初心者です。使用している本の素敵な部分を完成させた後(古くなった、または素晴らしい本ではないと考えられるかもしれません)、自分で試して、必要な場合にのみ本を参照していくつかの概念を強化することにしましたが、立ち往生しているように見える。私が取り組んでいる概念は、継承、ポリモーフィズム、抽象データ型(ADT)、およびクラスのコードをヘッダーファイル(.h)とC++ファイル(.cpp)に分離することです。テキストの壁に前もってすみません、私はちょうど私がいる必要がある場所を明確かつ具体的にしたいです。

したがって、私の目標は、該当する場合に相互に継承する単純な形状クラスを作成することです。 myPoly、myRectangle、myTriangle、mySquareの4つのクラスがあります。 myPolyは、この概念を正しく理解していれば、メソッドの1つが純粋な仮想関数(エリアメソッド)であるため、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を自動的に含める方法をいくつか読んでいます。誰かがそれについて何らかの洞察を提供できるなら、それは大歓迎です。包含ステートメントで引用符を使用することと山括弧を使用することの違いについても覚えています。以下は、私の小さなプロジェクト用に作成した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;
}

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

21
RIBdot

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

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

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

6
Code-Apprentice

コードの観点から(少なくとも私が見たもの)、それはかなり良いように見えますが、:

考慮すべき2つのことがあります:

  1. Cppファイルを直接含めないでください。たとえば、mySquare.hでは、#include "myRectangle.cpp"#include "myRectangle.h"。関数定義だけでなく、クラスの作成方法をプログラムに伝えるインターフェース/宣言をヘッダーファイルで提供する必要があります。

  2. 次に、すべてのオブジェクトファイルでコンパイルしていることを確認します。コードブロックはわかりませんが、g ++などを使用している場合は、g++ main.cpp myPoly.cpp mySquare.cpp etc.すべてのファイル。たとえば、myPoly.cppを忘れると、その関数の定義が含まれないため、このようなエラーが発生する可能性があります。

実際、すべてが正常に見えます。プログラムをリンクするときにmyPoly.objを含めないのと同じくらい簡単でしょう。私はCode :: Blocksに精通していません(かなり人気があることはわかっていますが)、たとえば、test.cppをクリックして「実行」を選択すると、Code :: Blocksはプログラムをビルドしようとしますその1つのソースファイルだけです。ビルドする各プログラムに関連するすべてのソースファイルを含める必要があります。