2

私は C++ の継承を学んでおり、Java 出身です。トレーニングするために、小さな Java の例を作成し、それを C++ に変換しようとしましたが、C++ の実装には多くの問題があります。

これは私のインターフェイス IShape.java です。Shape の抽象化を表します。

public interface IShape {
    public void draw();
}

そして、これは Shape を実装する私の Triangle.java です。

public class Triangle implements IShape{
    @Override
    public void draw() {
        //draw code
    }
}

そして今、Main.java:

public class Main {
    public static void main(String[] args) {
        IShape someShape = new Triangle();
        someShape.draw();
    }
}

Javaではすべてがうまく機能しますが、私のC++バージョンはコンパイルさえしません:S これは私のIShape.h C++ファイルです。これは、IShape.java インターフェイスに似ているはずです。

#ifndef ISHAPE_H_
#define ISHAPE_H_

class IShape{

public:
    virtual void draw() = 0;

    //must have this because of compiler
    virtual ~IShape();
private:
    //an awesome thing in c++ is that I can also define private methods for my children to implement!
    virtual int compute_point() = 0;
};

#endif

そして今、私の Triangle.cpp ファイル:

#include "IShape.h"

class Triangle: public IShape {

protected:
    int max_size;

public:
    Triangle(){
        max_size = 255;//This triangle has a limited max size!
    }

    void draw() {
        //implementation code here
    }

private:
    int compute_point() {
        //implementation code here
    }
};

最後に、私の C++ メイン:

#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#include "IShape.h"
#include "Triangle.cpp"

using namespace std;

int main( int argc, char *argv[]){

    IShape myShape = Triangle();
    myShape.draw();

    return EXIT_SUCCESS;
}

C ++メインにエラーが発生したことはありますか。いくつかの問題があるため、それらを列挙しようとします。

  1. 「mySHApe」が抽象的であることを教えてくれますが、それは三角形クラスで実装したからではありません!
  2. 最初のエラーを修正しても「myShape.draw()」を呼び出せません
  3. 私の友人は、cpp ファイルを含めるべきではないと言っています。しかし、三角形を含めない場合、Main.cpp はそれが存在することをどのように認識しますか?
  4. この例を C++ に移植するより良い方法はありますか? それとも、「Java を使いすぎている」のでしょうか。

私は c++ に関するいくつかのリンクとチュートリアルを読みましたが、それぞれが異なる方法で何かを教えてくれるため、多くの定義があり、少し混乱してしまいます。StackOverflow も検索しましたが、見つけた投稿は役に立ちませんでした。通常、より複雑な質問に言及しています。

コード スタイルを改善するために、どのようなヒントを提供できますか? また、テキストの壁で申し訳ありませんが、私は自分自身を説明し、反対票を投じないように努めています.

4

5 に答える 5

3

C ++では、ポリモーフィズムを実現するには、ポインターまたは参照を使用する必要があります。自動ストレージを備えたオブジェクトはスライスされ、あなたの場合、インスタンス化さえされません。実際、この指示は次のとおりです。

IShape myShape = Triangle();

タイプのオブジェクトをインスタンス化し、IShapeそれに一時Triangleオブジェクトを割り当てようとします。絶対にあなたが望むものではありません。一方、これは次のように機能します。

IShape* myShape = new Triangle(); // Using 
// ...
delete myShape;

ただし、最新のC ++では、通常、スマートポインターを使用することをお勧めします。main()次のように関数を書き直してみてください。

#include <memory> // For std::shared_ptr<>

int main( int argc, char *argv[])
{
    std::shared_ptr<IShape> myShape = std::make_shared<Triangle>();
    myShape->draw();

    return EXIT_SUCCESS;
}

また、定義を指定していない仮想デストラクタがあることにも注意してください。

virtual ~IShape();

提供する必要があります。最も簡単な方法は、次のように空のボディをインライン化することです。

virtual ~IShape() { }
于 2013-03-15T17:51:34.760 に答える
1

IShape myShape = Triangle();これは、IShapeインスタンスを作成してTriangleに割り当てようとしています。IShapeご存知のように抽象的であるため、これを行うことはできません。

必要なのはポインタです。

IShape* myShape = new Triangle();

また、交換してください:

virtual ~IShape();virtual ~IShape() {}

于 2013-03-15T17:51:37.547 に答える
1

これはすべて、ここでIShape オブジェクトをインスタンス化しようとしているという事実に起因しています。

IShape myShape = ...;

これは、RHSにあるものとは無関係です。コンパイラは、なぜそれができないのかを教えてくれます。IShapeポインター(または動的割り振りを使用している場合はスマートポインター)が必要です。この例では、簡単にするために自動ストレージ割り当てを使用していますが、これは詳細です。

Triangle t;           // default construct a Triangle object
IShape* myShape = &t; // IShape pointer points to a Triangle instance.
myShape->draw();      // calls Triangle::draw()

動的割り当ての例は次のようになります

std::unique_ptr<IShape> myShape(new Triangle());
myShape->draw();

その他の問題:

  1. デストラクタの実装がありません。空~IShape()の本体を指定して、派生クラスが必要のないときにデストラクタを実装するように強制されないようにします。
  2. 保護されたデータは、混乱を招くコードにつながる可能性があります。max_sizeプライベートにすることを検討する必要があります。
  3. コンストラクター本体でデータメンバーに値を割り当てるのではなく、コンストラクター初期化リストを使用してデータメンバーを初期化しますTriangle() : max_size(255) {}
于 2013-03-15T17:52:17.117 に答える
1

1)オブジェクトへのポインターではなく、実際のオブジェクトを宣言しているため、そうです。動的バインディングは、オブジェクトへのポインターにのみ適用されます。

これを見てみましょう:

IShape cShape = IShape();
Triangle cTriangle = Triangle();

どちらも構文的に正しいです。正しい型のオブジェクトを宣言しています。しかし、それは抽象的であるため、具体化することはできませんIShape

IShape pShape = Triangle();

構文的には正しいですが、pShape具体的であるため、そのためのスペースは既にスタックに予約されています。これは、IShape既にあるものに加えてすべてが破棄され、オブジェクト slicingで終了することを意味します。この状況ではポリモーフィズムを使用できません。

IShape* pTriangle = new Triangle();
pTriangle->draw();
...
delete pTriangle;

正解です。形状へのポインターを宣言し、動的に割り当てられた三角形のインスタンスで初期化しています。これは、Java での動作方法です (オブジェクトへの参照がある場合)。

3)実際には .cpp ファイルを含めるべきではありません。Triangleクラス宣言を からファイルに移動する必要が.cppあり.hます。次に、ボディ メソッドをヘッダー ファイルに実装するか、.cppTriangledrawメソッドを実装するファイルを作成するかを選択します。

于 2013-03-15T17:56:42.703 に答える
1

この行はあなたの問題です:

IShape myShape = Triangle();

一時的なオブジェクトを作成し、一時的な三角形をコピーしてオブジェクトTriangleを作成しようとします。IShapeしかしIShape、抽象的であるため、そのようなオブジェクトを作成することはできません。

Triangle必要なのは、オブジェクトへのハンドルを持つことです。C++ では、ハンドルには参照、ポインター、スマート ポインターの 3 種類があります。ほとんどの場合、スマート ポインターを使用する必要があります。

これを試して:

unique_ptr<IShape> myShape = new Triangle();

Java では、非プリミティブ型のすべての変数は、自動的にオブジェクトへのハンドルでした。C++ では、ハンドルと実際のオブジェクトの両方を変数に格納できるため、いつハンドルを使用するつもりで、どの種類を使用するかをコンパイラに伝える必要があります。

于 2013-03-15T17:52:48.237 に答える