从工厂创建的实例访问派生类的成员

时间:2015-10-22 20:40:18

标签: c++ scope polymorphism factory encapsulation

我有一个简单的Shape工厂示例,我可以在其中创建CircleSquare s。

我在contents类中添加了一个额外的“Circle”属性,该属性不属于Square派生类或Shape基类。

问题是,当我使用我的工厂创建Circle类的实例时,我无法修改所创建对象的contents

#include <iostream>

using namespace std;

// Shape base clas
class Shape {
public:

    // Shape constructor;
    Shape() {
        id_ = total_++;
    }

    // Virtual draw method
    virtual void draw() = 0;

protected:

    int id_;
    static int total_;
};
int Shape::total_ = 0;

// Circle derived class
class Circle : public Shape {
public:
    void draw() {
        contents = 0;
        cout << "circle " << id_ << ": draw, contents: " << contents << endl;
    }

    // Attribute to attempt to access
    int contents;
};

// Square derived class
class Square : public Shape {
public:
    void draw() {
        cout << "square " << id_ << ": draw" << endl;
    }
};

// Factory class
class Factory {
public:
    Shape* createCurvedInstance() {
        return new Circle;
    }
    Shape* createStraightInstance() {
        return new Square;
    }
};

// Main
int main()
{
    Factory* factory = new Factory;
    Shape* thing = factory->createCurvedInstance();

    // Draw method works fine (as it should)
    thing->draw();

    // Fails: "expression must have class type"
    thing.contents = 4;

    system("pause");

    return 0;
}

当我使用工厂创建派生类的实例时,如何访问派生类的属性?

3 个答案:

答案 0 :(得分:2)

除非你施放,否则你不会施放。多态的背后的整个想法是他们通过不可变接口使自己可用的实例。他们高度重视IS-A重播,其中Circle是一个形状,用于所有意图和目的,除了实现细节,没有人感兴趣。如果你公开添加内容&#39;对于你的Circle,它不再是一个Shape,所以它不应该通过工厂构建。

答案 1 :(得分:1)

由于Shape没有content,您无法从指向content 的指针修改Shape。完全停止。

但是,如果您知道您的特定Shape实际上是Circle并且content,则可以转换为指向Circle的指针。

void set_content(Shape*shape, int content)
{
  auto circle = dynamic_cast<Circle*>(shape);
  if(circle)
    circle->content = content;
}

此版本更安全:它不假设shapeCircle*,而是使用dynamic_cast<Circle*>,只有在shape所在的情况下才会返回非空事实是Circle*

dynamic_cast<>附带一些费用,您可能希望避免这些费用。如果您有任何其他简单的方法来确定您的shape实际上是Circle,则可以使用简单的static_cast<>

class Shape
{
public:
  virtual bool has_content() const { return false; }
  // ...
};

class ShapeWithContent : public Shape
{
public:
  bool has_content() const override { return true; }
  int content = 0; 
};

class Circle : public ShapeWithContent
{
  // ...
};

void set_content(Shape*shape, int content)
{
  if(shape->has_content())
    static_cast<ShapeWithContent*>(shape)->content = content;
}

说了这么多之后,我想强调一下,你应该尝试设计你的代码,使得这些技巧变得多余/不必要。

答案 2 :(得分:0)

事实证明我根本不需要工厂!

我真正想要的是某种容器类来容纳不同类型的形状。这两种形状都不是来自#include <iostream> using namespace std; // Circle class class Circle { public: Circle() { contents = 2; } void draw() { cout << "circle " << contents << endl; } int contents; }; // Square class class Square { public: void draw() { cout << "square" << endl; } }; // Shape containter class class ShapeContainer { public: Circle* getCircle() { return new Circle; } Square* getSquare() { return new Square; }; }; // Main int main() { ShapeContainer* container = new ShapeContainer; Circle* circle = container->getCircle(); circle->draw(); circle->contents = 42; circle->draw(); system("pause"); return 0; } 类,但可以通过它访问这两种形状。

Circle

这样我就可以同时生成SquareCircle,同时仍然可以访问{{1}}对象的内容!

有时你需要从全新的角度来看待事物,以获得你真正想要的功能......