2016-10-05 4 views
-4

私はGoogle talk on polymorphism and clean codeを見ていました。私はC言語で話者のJavaコードを++コピーC++での多型の実装

image

class Node{ 
    virtual double evaluate() = 0; 
}; 
class ValueNode :Node{ 
    double value; 
    double evaluate(){ 
     return value; 
    } 
}; 
class OpNode :Node{ 
    Node left; 
    Node right; 
    virtual double evaluate() = 0; 
}; 
class AdditionNode : OpNode{ 
    double evaluate(){ 
     return left.evaluate() + right.evaluate(); 
    } 
}; 
class MultiplyNode : OpNode{ 
    double evaluate(){ 
     return left.evaluate() * right.evaluate(); 
    } 
}; 

:それは

は、スピーカーは、1 + 2 * 3のような操作のためのクリーンなコードを作成する方法を説明しました。しかし、C++で

Node left; 
Node right; 

は、leftとrightが抽象クラスであり、したがって許可されていないNodeのオブジェクトであることを意味します。

これをどのように修正しますか。


編集:私は@Remyルボーによって与えられた提案に基づいてコードを変更しました。私は出力が7になると予想しましたが、代わりに687194771が得られました。

class Node { 
public: 
    virtual int evaluate() = 0; 
}; 

class ValueNode : public Node { 
public: 
    int value; 
    int evaluate() { 
     return value; 
    } 
}; 

class OpNode : public Node { 
public: 
    Node *left; 
    Node *right; 
}; 

class AdditionNode : public OpNode { 
public: 
    int evaluate() { 
     return left->evaluate() + right->evaluate(); 
    } 
}; 

class MultiplyNode : public OpNode { 
public: 
    int evaluate() { 
     return left->evaluate() * right->evaluate(); 
    } 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    ValueNode value1; 
    value1.value = 1; 

    ValueNode value2; 
    value1.value = 2; 

    ValueNode value3; 
    value1.value = 3; 

    MultiplyNode multiply; 
    multiply.left = &value2; 
    multiply.right = &value3; 

    AdditionNode add; 
    add.left = &value1; 
    add.right = &multiply; 

    int result = add.evaluate(); 
    cout << result; 

    return 0; 
} 

ここで私のエラー

+0

クラスValueNodeクラスとクラスAdditionNodeは、evaluate()宣言の前にプレフィックスvirtualを使用します。 – seccpur

+0

はおそらく 'Node *'(またはスマートポインタ)を使用します –

答えて

2

ポリモーフィズムだけワットの作品あなたはオブジェクトへのポインタ/参照を使います。 Javaでは、クラスオブジェクトは常に動的に割り当てられ、ポインタによって参照されます。だから、C++で、クラスの宣言は次のように検討する必要があります:

class Node { 
public: 
    virtual double evaluate() = 0; 
}; 

class ValueNode : public Node { 
public: 
    double value; 
    double evaluate() { 
     return value; 
    } 
}; 

class OpNode : public Node { 
public: 
    Node *left; 
    Node *right; 
}; 

class AdditionNode : public OpNode { 
public: 
    double evaluate() { 
     return left->evaluate() + right->evaluate(); 
    } 
}; 

class MultiplyNode : public OpNode { 
public: 
    double evaluate() { 
     return left->evaluate() * right->evaluate(); 
    } 
}; 

をそして、あなたは、このように例式1+(2*3)を設定することができます。add.evaluate()が呼び出されると

ValueNode value1; 
value1.value = 1; 

ValueNode value2; 
value2.value = 2; 

ValueNode value3; 
value3.value = 3; 

MultiplyNode multiply; 
multiply.left = &value2; 
multiply.right = &value3; 

AdditionNode add; 
add.left = &value1; 
add.right = &multiply; 

double result = add.evaluate(); 

、それが返されますleft->evaluate()right->evaluate()を呼び出すことによって返された値の合計。leftvalue1を指し、rightmultiplyを指している。

value1->evaluate()が呼び出されると、valueフィールド(1)が返されます。

multiply->evaluate()が呼び出されると、それはleftvalue2rightで指しているleft->evaluate()right->evaluate()を呼び出すことによって返された値の積がvalue3で指して返します。

value2->evaluate()が呼び出されると、valueフィールド(2)が返されます。

value3->evaluate()が呼び出されると、フィールドが返されます。3です。

したがって、add.evaluate()は、12*3の合計を返します。これは7です。

+0

左右のノードにはメモリアドレスが格納されています。彼らは、その場での操作でどのように値を評価しますか? – roang

+0

@roang:これは ' - >'のことです。メソッドを呼び出すために 'xy()'を使うとき、 'x-> y()を使うと' x'は生の値でなければならず、 'typename&x'で宣言されたC++シームレス参照型) '、' x'は逆参照されて 'y'を見つけて呼び出すポインタ(またはポインタのようなもの、例えばイテレータ)です。 – ShadowRanger

+0

@roang: 'left-> evaluate()'または 'right-> evaluate()'を呼び出すと、コンパイラはポインタを参照して実際の 'Node'オブジェクトに到達し、' evaluate() 'を呼び出します。 'evaluate()'は仮想であるため、 'ValueNode :: evaluate()'、 'MultiplyNode :: evaluate()'、 'AdditionNode :: evaluate()'のいずれであっても、最も派生した実装にディスパッチされます。ポインタが指しているオブジェクトのタイプによって異なります。多態的メソッドがどのようにディスパッチされるかについて具体的な詳細を知りたければ、仮想メソッドテーブルがどのように機能するかを説明する良いC++ブックを入手するべきです。 –

0

これをどのように修正しますか?

Nodeの代わりにNode*を使用してください。

class OpNode : public Node{ 
    Node* left; 
    Node* right; 

    // There is no need to redeclare a pure virtual function. 
    // virtual double evaluate() = 0; 
}; 
0

あなたは左と右のポインタを行う必要があります。

Node* left; 
Node* right; 
0

あなただけの同等のC++構文にJavaコードをコピーして、それが動作するように期待することはできません。

C++オブジェクトは、Javaオブジェクトとはまったく異なる方法で動作します。 C++オブジェクトとJavaオブジェクトを比較することはできません。彼らは根本的に異なっています。

C++、Javaのオブジェクトと等価では、参照カウントのオブジェクトになり、std::shared_ptrのように、同等のC++擬似コードので(自分のスタイルを模倣)のようになります。

class OpNode :Node{ 
    std::shared_ptr<Node> left; 
    std::shared_ptr<Node> right; 
    virtual double evaluate() = 0; 
}; 

典型的なサブクラスされた状態で:

class AdditionNode : OpNode{ 
    double evaluate(){ 
     return left->evaluate() + right->evaluate(); 
    } 
}; 

私は、このようなプライベート/パブリック・アクセス・クラス、などなどあなたが取り残さ同じ内容を、除外しています...

+0

left-> evaluate()+ right-> evaluate(); 左と右は抽象クラスであるノード型なので、 – roang

+0

抽象クラスで他の仮想メソッドを呼び出すのと同じです。 –

+1

@roang: 'evaluate()'は仮想メソッドです。基本クラスへのポインタ/参照を使用して仮想メソッドを呼び出すと(基本クラスが抽象クラスであるかどうかにかかわらず)、そのメソッドのオブジェクトから最も派生した実装に呼び出しが送出されます。したがって、 'Node *'ポインタで 'evaluate()'を呼び出すと、実際には 'ValueNode :: evaluate()'、 'MultiplyNode :: evaluate()'、または 'AdditionNode :: evaluate()'が呼び出されます。 'Node *'ポインタが実際に指している派生オブジェクトのタイプに依存します。 –