2

だから私はこれらのヘッダファイルを持っています:

シェイプ.h:

class Shape
{
public:
    Shape();
    virtual ~Shape();
    virtual double getArea();
    virtual void printDraw();
    bool isLegal(Shape shape);
};

三角時間:

class Trig : public Shape
{
public:
    Trig(Point pointA, Point pointB, Point pointC);
    virtual ~Trig();
    virtual double getArea();//override
    virtual void printDraw();//override
    bool isLegal(Trig trig);//override
};

しかし、Trig.cpp を実装しようとすると、エラーが発生します。私は試した :

Trig::Trig(Point pointA, Point pointB, Point pointC) {..}

インターネットで調べてみましたが、継承をきちんとしていないようです。[私のコードには、宣言のみを含むヘッダー ファイルが必要です!... 割り当ての要件!]

C++で継承と仮想関数の両方を使用するのは初めてです[Javaで継承を使用しました]

そして、仮想関数に関して..通常の関数よりも実装に違いはありますか? 【動作の違いが分かりました】。

4

2 に答える 2

4

コメントであなたはそれを説明します

「エラーが発生しました: `Shape::Shape()' への未定義参照」

これは、そのコンストラクターの実装を提供するのを忘れたことを意味します。

技術的な問題が修正されたので、設計を見てみましょう。

最初の 2 つのメソッドには 2 つの問題があります: (1) オブジェクトを変更するべきではありませんが、宣言されていconstないため、オブジェクトに対して呼び出すことはできません。const(2)get接頭辞によって読みやすさが低下し、タイプする必要があり、一般的なものはありません。アドバンテージ。getいくつかのまれな状況では、あいまいさを解消するデバイスとしてプレフィックスが役立つことがわかりましたが、初心者が見たすべての使用法は、Java 規則の不適切なコピーであり、Java では意味がありますが、C++ では意味がありません。だから、代わりに…

virtual double getArea();
virtual void printDraw();

行う

virtual double area() const;
virtual void print() const;

では、方法は…

bool isLegal(Shape shape);

多くの点で間違っています…痛い!しかし、純粋に技術的なことから始めましょう。

純粋に技術的な観点からは、引数を値で渡すのは不必要に非効率的であり、呼び出しごとにコピー操作が発生します。代わりに、参照によってオブジェクトを渡します。オブジェクトと右辺値オブジェクトを引数としてconstサポートするために、それを への参照にします。const

bool isLegal(Shape const& shape);

次に、naming:isLegalは不適切な名前です。これは、ほとんどの C++ オブジェクトが有効であるためです。違法になるためには、たとえば、ポルノであり、西洋以外の国に住んでいる必要があります. そして、オブジェクトをポルノグラフィーにしたり、特定の地理的地域に配置したりする方法は、一生考えられません。

そう、

bool isValid(Shape const& shape);

次に、低レベルの設計です。非メソッドを通常のメンバー関数として持つ正当な理由はありませんvirtual。オブジェクトで呼び出す必要があるからです。しかし、必要な情報はすべて通常の引数にあります。この混乱は、派生クラスで確認できます。ここでは…

bool isLegal(Trig trig);//override

はまったくオーバーライドではありません。技術的には関数名のオーバーロードです。つまり、同じ名前の別の関数です。ここには仮想性はなく、オーバーライドもありません。そして、それは必要ありません。

したがって、staticオブジェクトで呼び出す必要のないメンバー関数にします。

static bool isValid(Shape const& shape);

最後に、より高いレベルの設計である C++ コンストラクターとデストラクタの全機構は、そのようなメソッドとチェックを回避するために存在します。

アイデアは、あなたが…

  • すべてのコンストラクターで有効なオブジェクトを確立します。

  • すべてのメソッドでオブジェクトを有効に保ちます。

その後、オブジェクトは単に無効になることはありません。このアプローチは単相構築と呼ばれ、それを「有効」にするオブジェクトのプロパティは、クラスのクラス不変量として知られています。これは、すべてのコンストラクターによって確立され、すべてのメソッドによって維持される必要があります。

これは、最終バージョン、isValid関数IS REMOVEDを意味します。その仕事はコンストラクターとメソッドによって(適切に)行われるため、実行する仕事はありません。

さて、単一フェーズの構築には技術的な課題がいくつかあります。特に、基本クラスのコンストラクターで派生クラス固有の初期化を行う方法です。これはC++ FAQでカバーされています。多くの場合、FAQ を読むことをお勧めします。

于 2012-09-15T12:27:18.530 に答える
1

最初のバージョンは正しいです:

Trig::Trig(Point pointA, Point pointB, Point pointC) {..}

コンパイルはしますが、リンクしません。その理由は、 のパラメーターなしのコンストラクターを宣言しましたが、定義Shapeに失敗したためです。定義を追加する

Shape::Shape() {..}

または、デフォルトのコンストラクターに問題がない場合は、Shape のヘッダーから宣言を削除します。

于 2012-09-15T12:04:47.687 に答える