2017-08-11 2 views
1

Les classes Rectangle et Triangle sont toutes deux dérivées de Shape. Je veux ajouter une autre classe ComplexShape, qui peut être n'importe quelle forme spécifique avec d'autres formes attachées à elle.Le comportement d'une fonction membre d'une classe dérivée peut-il être déterminé par la classe par laquelle elle est instanciée?

Je sais qu'il existe des solutions simples pour résoudre ce problème, comme déclarer une variable pour stocker des propriétés de forme dans la classe de base, mais je suis plus intéressé par les moyens d'adresser la question de titre. Comment puis-je, si possible, définir le constructeur de ComplexShape, de sorte que ComplexShape utilise les méthodes de la classe utilisée pour l'initialiser?

#include <iostream> 
#include <memory> 
#include <vector> 

class Shape { 
    public: virtual unsigned int getPointCount() const = 0; 
}; 

class Rectangle : public Shape { 
    public: unsigned int getPointCount() const { return 4; } 
}; 

class Triangle : public Shape { 
    public: unsigned int getPointCount() const { return 3; } 
}; 

class ComplexShape : public Shape { 
public: 
    std::vector<std::shared_ptr<Shape>> children; 

    //What Constructor comes here? 

    unsigned int getPointCount() const { 
     unsigned int i{ 0u }; 
     for(auto shape : children) i += shape->getPointCount(); 
     return i; 
    } 
}; 

int main() { 
    Triangle triangle(); 
    ComplexShape arrow; //How do I initialize this as a rectangle? 
    arrow.children.push_back(std::shared_ptr<Shape>(new Triangle())); 
    std::cout << arrow.getPointCount(); 
    return 0; 
}; 
+2

Vous déclarez qu'une forme complexe est une collection de formes, pourquoi ne pas mettre en œuvre comme ça? Je ne vois pas le besoin de "promouvoir" l'une des formes comme la forme "de base" comme vous le demandez. –

+1

Pour répondre à la question dans le titre: Je pense que non. Vous pouvez l'implémenter en tant que modèle, puis vous avez un membre fortement typé pour faire référence à la forme "principale". (Je suis un développeur C#, je m'excuse si ma formulation est incorrecte, je parle des génériques C#) –

+0

Recherche ** Motif composite **, cela vous donnera une idée de la façon de l'implémenter. En passant, votre variable «enfants» devrait être privée. Comme indiqué dans d'autres commentaires, il serait probablement préférable que la forme "principale" figure dans la liste des enfants. – Phil1970

Répondre

0

Vous pouvez essayer avec la liste des initialiseur utilisés dans le constructeur: http://www.cplusplus.com/reference/initializer_list/initializer_list/

#include <iostream> 
#include <memory> 
#include <vector> 
#include <initializer_list> 

class Shape { 
public: virtual unsigned int getPointCount() const = 0; 
}; 

class Rectangle : public Shape { 
public: unsigned int getPointCount() const { return 4; } 
}; 

class Triangle : public Shape { 
public: unsigned int getPointCount() const { return 3; } 
}; 

class ComplexShape : public Shape { 
public: 
    std::vector<std::shared_ptr<Shape>> children; 
    ComplexShape() {} 

    ComplexShape(std::initializer_list<std::shared_ptr<Shape>> init) : children(init) 
    { 
     // do some dynamic_cast magic here 
    } 

    unsigned int getPointCount() const { 
     unsigned int i{ 0u }; 
     for (auto shape : children) i += shape->getPointCount(); 
     return i; 
    } 
}; 

int main() { 
    Triangle triangle(); 
    ComplexShape arrow; //How do I initialize this as a rectangle? 
    arrow.children.push_back(std::shared_ptr<Shape>(new Triangle())); 
    std::cout << arrow.getPointCount(); 

    // This could be simplified probably 
    ComplexShape rect = { std::shared_ptr<Shape>(new Triangle()), std::shared_ptr<Shape>(new Triangle()) }; 
    return 0; 
};