我有一个简单的Shape
工厂示例,我可以在其中创建Circle
或Square
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;
}
当我使用工厂创建派生类的实例时,如何访问派生类的属性?
答案 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;
}
此版本更安全:它不假设shape
是Circle*
,而是使用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
这样我就可以同时生成Square
和Circle
,同时仍然可以访问{{1}}对象的内容!
有时你需要从全新的角度来看待事物,以获得你真正想要的功能......