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

Accessing members of a derived class from a factory created instance

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

我在 Circle class 中添加了一个额外的“contents”属性,它不属于 Square 派生的 class 或 Shape基础class.

问题是,当我使用我的工厂创建 Circle class 的实例时,我无法修改创建对象的 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;
}

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

没办法,除非你施法,而你不得施法。多态背后的整个想法是它们通过不可变接口使自己可用的实例。他们强调了 IS-A 关系,其中 Circle 是所有意图和目的的 Shape,除了实现细节,没有人对此感兴趣。如果你公开添加 'contents' 到你的 Circle,它就不再是 Shape,所以它不应该通过工厂来建造。

由于 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*>,只有在 return 非空 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;
}

说了这么多,我想强调的是,您应该尝试以制造此类技巧的方式设计代码 redundant/unnecessary。

原来我压根就不想建工厂!

我真正想要的是某种容器 class 来容纳不同类型的形状。这两种形状都不是从 ShapeContainer class 派生的,但是可以通过它访问这两种形状。

#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;
}

这让我可以创建 Circles 和 Squares,同时仍然能够访问 Circle 对象的内容!

有时您需要从全新的角度看待事物才能获得您真正想要的功能...