我对问题标题不满意,但我无法很好地描述它。为了简洁起见,我将实现放在类声明中。
我有一个这样的课程:
class VisibleObject {
public:
void draw(sf::RenderWindow& rw) {
rw.draw(*shape.get());
}
virtual void setSize(sf::Vector2f) = 0;
protected:
std::shared_ptr<sf::Shape> shape;
}
sf::Shape
是一个抽象类。然后我有一个像这样的派生类:
class Brick : VisibleObject {
Brick() {
shape.reset(new sf::RectangleShape());
}
void setSize(sf::Vector2f newSize) {
std::dynamic_pointer_cast<sf::RectangleShape>(shapes).get()->setSize(newSize);
}
}
sf::RectangleShape()
是一个继承自sf::Shape
和setSize()
的具体类,是为它定义的,而不是sf::Shape
,这就是我需要强制转换的原因。
当然,我需要做一些错误处理,如果动态转换失败并返回一个空的shared_ptr。
我这样做是因为我希望能够只定义一次draw
方法,因为在这个简单的游戏中,每个对象都会以这种方式绘制其成员。最初我将形状从基类中删除,例如Brick只有自己的私有sf::RectangleShape
,可以在堆栈上实例化;这是干净的,但是必须为每种对象类型重写draw方法。
这样可行,但使用起来更麻烦并引入堆分配。我也有shared_ptr
开销(我会使用unique_ptr
,但我需要动态投射)。
这是我做我想做的最合适的方式吗?
答案 0 :(得分:3)
最好将接口保持为接口,而不是开始强制实现细节。所以只需要一个像我这样的空基类:
class VisibleObject
{
public:
~VisibleObject() {}
virtual void draw(sf::RenderWindow & window) = 0;
virtual void setSize(sf::Vector2f const & size) = 0;
};
您可以将形状存储粘贴到实现此接口的具体类中。
此外,Shape
应提供虚拟调整大小的方法:
class Shape
{
public:
virtual ~Shape() {}
virtual void resize(sf::Vector2f const & size) = 0;
};
现在你可以说VisibleShapeObject
作为中间基类:
class VisibleShapeObject : public VisibleObject
{
public:
virtual void draw(sf::RenderWindow & window) override final
{
window.draw(*shape_);
}
virtual void setSize(sf::Vector2f const & size) override final
{
shape_->resize(size);
}
protected:
std::shared_ptr<Shape> shape_; // or unique_ptr<Shape>
};
答案 1 :(得分:1)
你没有分享你想要做的一切,但这只是一种方式:
template<ShapeT>
class VisibleObject {
public:
void draw(sf::RenderWindow& rw) {
rw.draw(*shape.get());
}
virtual void setSize(sf::Vector2f) = 0;
protected:
std::shared_ptr<ShapeT> shape;
void reset(ShapeT* shape) {
this->shape = shape;
}
}
class Brick : VisibleObject<sf::RectangleShape> {
Brick() {
shape.reset(new sf::RectangleShape());
}
void setSize(sf::Vector2f newSize) {
shape->setSize(newSize);
}
}
可能有理由说这不适合你,但没有更多的洞察力,我无法猜测是什么。
答案 2 :(得分:1)
为什么不简单地介绍一种从具体类中检索std::shared_ptr<sf::Shape>
的方法,而不是强制要求sf::Shape&
中存储?
class VisibleObject {
virtual sf::Shape& getShape() = 0;
public:
void draw(sf::RenderWindow& rw) {
rw.draw(getShape());
}
virtual void setSize(sf::Vector2f) = 0;
};
class Brick : VisibleObject {
sf::RectangleShape shape;
sf::Shape& getShape() override { return shape; }
public:
void setSize(sf::Vector2f newSize) override {
shape.setSize(newSize);
}
};
当你只能存储一个普通的旧成员时,通过一个指向base的指针存储,引入间接和向下转发以及引用计数开销似乎很荒谬。事实上,如果我正确地理解了这个问题,你可能会使用一个模板来生成具体的类并避免大量的样板:
class VisibleObject {
public:
virtual ~VisibleObject() {}
virtual void draw(sf::RenderWindow&) = 0;
virtual void setSize(sf::Vector2f) = 0;
};
template <typename Shape>
class VisibleConcreteObject : public VisibleObject {
Shape shape;
public:
void draw(sf::RenderWindow& rw) override /* final? */ {
rw.draw(shape);
}
void setSize(sf::Vector2f newSize) override /* final? */ {
shape.setSize(newSize);
}
};
typedef VisibleConcreteObject<sf::RectangleShape> Brick;