2017-06-21 16 views
2

私は、is-a対a-like-aの関係を理解し​​ようとしています。私はどこかに、私たちは常に、のような。形状基本クラスと導出された三角形と円クラスの古典的な例を考えてみましょう。だから円はシェアなので、三角形は形です。関数表示領域は、基本クラスで定義されています。今すぐベロープログラムが正常に動作します。円と三角形で形状クラスを設計する

#include "stdafx.h" 
#include<cmath> 
#include <iostream> 

class shape 
{ 
public: 
    virtual void displayArea()=0; 
}; 


class circle :public shape 
{ 
    int radius; 
public: 
    circle(int radius2) :radius(radius2){ } 
    void displayArea() 
    { 
     double area = 3.14*radius*radius; 
     std::cout << " \n Area circle" << area<<std::endl; 
    } 
}; 

class triangle :public shape 
{ 
    double a,b,c; 
public: 
    triangle(double a1, double b1, double c1): a(a1), b(b1),c(c1) 
    { 
     if (a + b > c && a + c > b && b + c > a) 
      std::cout << "The sides form a triangle" << std::endl; 
     else 
      std::cout << "The sides do not form a triangle. Correct me !" << std::endl; 

    } 

    void displayArea() 
    { 


     double s = (a + b + c)/2; 
     double area = sqrt(s*(s - a)*(s - b)*(s - c)); 
     std::cout << " \n Area triangle"<< area<<std::endl; 
    } 
}; 

void main() 
{ 
    shape * p1[2]; 
    p1[0]= new circle(20); 

    p1[1] = new triangle(5.6,8.1,10.3); 
    for (int i = 0; i < 2; ++i) 
    { 
     p1[i]->displayArea(); 
    } 

    int y; 
    std::cin >> y; 
} 

要件は1つが、その後どのように私は私が-される関係が変更されないように私のクラスを変更する必要があり、ユーザのパラメータに基づいて形状の各パラメータが変更されたmodifyShape機能を実装する必要があるとなれば。私が見ると、円で囲まれた単一の引数modifyShapeと、三角で囲まれた3つの引数modifyShapeを定義しなければならないと感じています。しかし、この関数は基本クラスのようにどのように見えるでしょうか?

オプション1:私は単一の引数と2つの引数modifyShapeの形を定義しますが、それは私が円で余分な2つの引数関数と余分な1つの引数関数を持つことを意味します。

オプション2:可変引数関数modifyShapeを定義していますが、どういうわけか、これは私には見えません。

+0

私は約IS様聞い​​たことがありません。この関係をどう定義しますか? –

+0

"modifyShape関数ここで、シェイプの各パラメータは、ユーザーのパラメータに基づいて変更されます。"これは、明確な要件のようには見えません。 「ユーザーのパラメータに基づいて」とはどういう意味ですか?ユーザーが5を入力し、(7,8)の単位三角形と(1、-2)を中心とする単位円がある場合、予想される結果はどうなりますか? –

答えて

0

3つ目のオプションがあります。各シェイプのパラメータを表すクラス (または構造体)の新しい階層を作成できます。次に、 ポインタを仮想関数の引数として基本クラスに渡すことができます。たとえば :

struct ShapeParams 
{ 
    ... 
} 

struct TriangleParams : public ShapeParams 
{ 
    double a; 
    double b; 
    double c: 
} 
class shape 
{ 
    public: 
    virtual void displayArea()=0; 
    modifyShape (ShapeParams*) = 0; 
}; 

class triangle :public shape 
{ 
    public: 
    void modifyShape (ShapeParams*) = override; 

    private: 
    TriangleParams m_params; 
} 
+0

これは悪いアドバイスです。 modifyShape実装では、ShapeParamsパラメータをキャストする必要があります。エラーが起こりやすく、何も得られません。 TriangleParamsを三角形に渡す必要があります。 –

+0

私は確かにキャストが必要ですが、常に同じタイプのShapeParamsで動作するスコープ内で行われます。他のクラスにポインタを渡すと危険ですが、これはほとんど何でも言えることです。 このようにして得られるのは、形状を使って作業を一般化するために使用できる仮想呼び出しです。たとえば、Template Method Design Patternを使用すると便利です。 – user8160628

0

あなたは、クラスを少しあなたを再構築できますが、それは別の独立したクラスが必要になります。 2Dと3Dの数学的なベクトルクラスのセットを作成することができますが、ベクターによって加算、減算、掛け算、スカラーなどのベクトルが行うことができるすべてのオーバーロードされた演算子と数学関数を持つ必要があります。クロス製品は心配する。メソッド、長さなどを正規化する必要があります。一度あなたはこれらの働く数学ベクトルクラスを持っています。次に、ベクトルを使用して形状クラスを再設計することができます。または、独自のベクトルクラスを作成する代わりに、OpenGLでの作業に使用されるGLMの数学ライブラリなどの数学ライブラリクラスを使用できます。これはフリーでオープンソースであり、ヘッダーのみのライブラリでもあります。パスにライブラリをインストールしたら、ヘッダをインクルードするだけです。リンクについて心配する必要はありません。そして、これらのベクトルのクラスでそれを行うのは、あなたの形状クラスで数学をより容易になり、形状クラスを設計するために容易になるだろう。そして、継承され

#include <glm\glm.hpp> 
// Needed If Doing Matrix Transformations: Rotation, Translation Scaling etc. 
// #include <glm\gtc\matrix_transform.hpp> 

class Shape { 
public: 
    enum Type { 
     NONE = 0, 
     TRIANGLE, 
     SQUARE, 
     CIRCLE, 
    }; 
protected: 
    Type type_; 
    glm::vec4 color_ { 1.0f, 1.0f, 1.0f, 1.0f }; // Initialize List Set To White By Default 
    double perimeter_; // Also Circumference for Circle 
    double area_;  
    // double volume_; // If in 3D. 
public: 
    // Default Constructor 
    Shape() : type_(NONE), color_(glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)) {}  
    // User Defined Constructors 
    // Sets Shape Type Only Color Is Optional & By Default Is White 
    explicit Shape(Type type, glm::vec4 color = glm::vec4()) : type_(type), color_(color) {} 

    Type getType() const { return type_; } 
    void setType(Shape::Type type) { 
     if (type_ == NONE) { 
      // Its okay to set a new shape type 
      type_ = type; 
      } 

      // We Already Have a Defined Shape 
      return; 
     } 

     // Getters That Are Commonly Found Across All Shapes 
     double getPerimeter() const { return perimeter_; } 
     double getArea() const { return area_; } 

     // Common Functions that can be done to any shape 
     void setSolidColor(glm::vec4 color) { color_ = color }; 
     glm::vec4 getColor() const { return color; } 

     // Common Interface That All Shapes Share But Must Override 
     virtual double calculateArea() = 0; 
     virtual double calculatePerimeter() = 0; 

     // Since we do not know what kind of shape to modify until we have one 
     // to work with, we do not know how many parameters this function will need. 
     // To get around this we can use a function template and then have overloads 
     // for each type we support 
     template<typename Type = Shape> 
     virtual void modify(Type* pShape /*,glm::vec3... params*/); 

     // Overloaded Types: - Should Be Defined & Overridden By the Derived Class 
     virtual void modify<Triangle>(Triangle* pTriangle, glm::vec3, glm::vec3, glm::vec3, glm::vec4 = glm::vec4()) { /* ... */ } 
     virtual void modify<Circle>(Cirlce* pCircle, float radius, glm::vec4 color = glm::vec4()) { /* ... */} 

}; 

:ここでは擬似コードはどのように見えるかの例ですクラスは次のようになります。

class Triangle : public Shape { 
public: 
    // Could Be An Option To Where This is a base class as well to specific types of triangles: 
    enum TriangleType { 
     Acute = 0, 
     Right, 
     Equilateral, 
     Obtuse 
    } // then each of these would have properties specific to each type 
private: 
    glm::vec3[3] vertices_; 

public: 
    // Default Constructor 
    Triangle() : Shape(TRIANGLE) {} // Sets The Shape Type But Has No Vertices Or Area; just default construction 
    // Vertices But No Color 
    Triangle(glm::vec3 A, glm::vec3 B, glm::vec3 C) : Shape(TRIANGLE) { 
     vertices_[0] = A; 
     vertices_[1] = B; 
     vettices_[2] = C; 

     // Call These To Have These Values 
     calculatePerimeter(); 
     calculateArea();    
    } 
    // Vertices & Color 
    Triangle(glm::vec3 A, glm::vec3 B, glm::vec3 C, glm::vec4 color) : Shape(TRIANGLE) { 
     vertices_[0] = A; 
     vertices_[1] = B; 
     vertices_[2] = C; 

     calculatePerimeter(); 
     calculateArea(); 
    } 

    // No Need To Do The Set & Get Colors - Base Class Does that for you. 

    // Methods that this shape must implement 
    virtual double calculateArea() override { 
     // Calculations For Getting Area of A Triangle 
     area_ = /* calculation */; 
    }; 
    virtual double calculatePerimeter() override { 
     // Calculations For Getting Perimeter of A Triangle 
     perimeter_ = /* calculation */; 
    }; 

    void modify<Triangle>(Triangle* pTriangle, glm::vec3, glm::vec3, glm::vec3, glm::vec4 = glm::vec4()) override { /* ... */ } 

}; 

ここで情報を表示します。個人的に私はこれらのクラスでこれを実装しません。ただ、ちょうどこのようなgettersを使用して購入画面やファイルに値を印刷するには、あなたの標準std::coutstd::ofstreamなどを使用します。

#include <iostream> 
#include "Triangle.h" 

int main() { 
    Triangle t1(glm::vec3(0.0f, 1.0f, -1.3f), // Vertex A 
       glm::vec3(3.2f, 5.5f, -8.9f), //  B 
       glm::vec3(-4.5f, 7.6f, 8.2f), //  C 
       glm::vec4(0.8f, 0.9f, 0.23f, 1.0f)); // Color 

    std::cout << "Perimeter is " << t1.getPerimeter() << std::endl; 
    std::cout << "Area is " << t1.getArea() << std::endl; 

    return 0; 
} 
関連する問題