没有抽象方法的抽象类
Posted
技术标签:
【中文标题】没有抽象方法的抽象类【英文标题】:Abstract class without abstract methods 【发布时间】:2011-07-10 16:21:47 【问题描述】:是否可以在不声明任何抽象方法的情况下在 C++ 中创建类抽象?目前,我有一个带有 StaticSprite 和 DynamicSprite 子类的 Sprite 类。我想让 Sprite 类抽象化。
问题是他们没有共享任何方法。好吧,StaticSprite 和 DynamicSprite 可能共享一个 draw() 方法,但是这个方法的参数不同,所以这不是一个选项。
谢谢!
编辑: 这是演示我正在尝试做的代码:
精灵:
class Sprite
public:
Sprite(HINSTANCE hAppInst, int imageID, int maskID);
~Sprite();
protected:
HINSTANCE hAppInst;
HBITMAP hImage;
HBITMAP hMask;
BITMAP imageBM;
BITMAP maskBM;
HDC hSpriteDC;
;
静态精灵:
class StaticSprite : public Sprite
public:
StaticSprite(HINSTANCE hAppInst, int imageID, int maskID);
~StaticSprite();
void draw(Position* pos, HDC hBackbufferDC);
;
动态精灵:
class DynamicSprite : public Sprite
public:
DynamicSprite(HINSTANCE hAppInst, int imageID, int maskID);
~DynamicSprite();
void draw(HDC hBackbufferDC);
;
如您所见,创建一个 Sprite 对象是没有用的,所以我想将该类抽象化。但我不能使 draw() 抽象,因为它使用不同的参数。
【问题讨论】:
为什么要抽象没有抽象方法? 他们可能不希望它被实例化 拥有一个没有方法可继承的基类有什么意义? 因为那个类只有一些字段和一个构造函数/析构函数,但是类的行为应该由子类来实现。我知道这在 Java 中是可能的,所以我想知道 c++ 是否也支持这个。 我已经添加了我的代码来演示我正在尝试做的事情。 【参考方案1】:你可以将你的析构函数声明为纯虚函数,因为所有类都有一个。
class AbstractClass
public:
virtual ~AbstractClass() = 0 ;
;
但是,您需要在别处定义此析构函数。
AbstractClass::~AbstractClass()
【讨论】:
由于基类析构函数是虚拟的,派生类析构函数的析构函数将在需要的时间和地点被调用。应该没有问题。 @Bv202 - 您还提供了析构函数的实现,因此您可以在那里进行清理。 @Bv202 你仍然可以实现一个纯虚析构函数来清理内存。 好吧,这可能是也可能不是 OP 想要的——它确实增加了类的开销并改变了语义。 如果它包含数据管理,它不是很抽象,是吗?另一种选择是使析构函数受到保护。你确实从中获得了那种力量,因为它不能单独被摧毁。【参考方案2】:如果类什么都不做,什么也不提供,只是作为一个标记存在,没有理由担心它是否是抽象的。这基本上不是问题。
如果您绝对希望确保除了在继承上下文之外永远不会实例化,请使用protected constructors。
请避免制作纯虚析构函数。疯狂的谎言就是这样。
【讨论】:
【参考方案3】:没有。
你当然可以用这个:
class Sprite
;
当然,当您尝试创建它的实例时,编译器不会抱怨。
你可以添加一个纯虚析构函数:
class Sprite
public:
virtual ~Sprite () = 0;
;
或者你可以保护构造函数,停止实例化:
class Sprite
protected:
Sprite ();
;
【讨论】:
【参考方案4】:针对你帖子的具体情况,考虑私有继承。这样你就可以懒惰地使用基础的实现,而不会向世界宣传虚假的 IS-A 关系。
【讨论】:
【参考方案5】:传统的做法是制作一个纯虚析构函数,然后实现它。
// .h
struct Foo
virtual ~Foo() = 0;
;
// .cpp
Foo::~Foo()
【讨论】:
不能实现纯虚拟。 @Cthutu 其实你可以实现纯虚方法。这只是意味着孩子必须再次实现它。 在析构函数的情况下,你必须。 是的,你可以,参见例如10.4/2:“纯虚函数仅在使用限定 ID 语法 (5.1) 显式调用时才需要定义。”和 12.4/7:“析构函数可以声明为虚拟 (10.3) 或纯虚拟 (10.4);如果在程序中创建了该类或任何派生类的任何对象,则应定义析构函数。如果类具有基类具有虚拟析构函数的类,其析构函数(无论是用户声明的还是隐式声明的)都是虚拟的。”【参考方案6】:问题是没有 他们共享的方法。
嗯,你的问题就在那里。你不应该在这里使用继承!如果您不打算用一个班级代替另一个班级,那么他们就不应该处于父子关系中。
根据需要,它们应该是完全不相关的、模板或使用组合。
编辑:根据代码示例,您继承以重用,我建议改用组合。 Sprite
可以是 struct
,由 DynamicSprite
和 StaticSprite
拥有。您可以根据需要将尽可能多/少的辅助逻辑放入Sprite
。
【讨论】:
我在第一篇文章中添加了代码。应该怎么解决? -1 因为你不可能知道是否应该使用继承。查看 Alexandrescu 的访问者框架,以找到与您的陈述形成鲜明对比的观点。【参考方案7】:最好的方法是保护类的构造函数,这样类就不能被直接实例化,因此它本质上是抽象的:
class SomeBaseClass
protected:
SomeBaseClass()
SomeBaseClass(const SomeBaseClass &)
SomeBaseClass &operator=(const SomeBaseClass&)
public:
virtual ~SomeBaseClass()
...
;
或者,更新的样式:
class SomeBaseClass
protected:
SomeBaseClass() = default;
SomeBaseClass(const SomeBaseClass &) = delete;
SomeBaseClass &operator=(const SomeBaseClass&) = delete;
public:
virtual ~SomeBaseClass() = default;
...
;
析构函数通常最好保持公开,因为您可能希望通过其基类指针删除一个对象。
【讨论】:
【参考方案8】:要创建一个不派生就无法实例化的纯抽象类 - 您必须至少定义一个抽象方法。
例如。
virtual void blah() const = 0;
否则你可以使用任何类作为抽象类
【讨论】:
最终,问题是“为什么要打扰”? @Randolpho - 问题变了。你的意思是为什么要有一个抽象类,或者如果它没有方法为什么要抽象? 是的,问题变了。我讨厌这种情况发生。 :)【参考方案9】:如果您确实必须使用继承,请考虑使用非虚拟接口 (NVI) 习惯用法(请参阅http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.3)
基本上,基类将定义一组重载的非虚拟方法,这些方法从派生类中调用受保护的纯虚函数。
你绝对不想做的是重载一个虚函数(看起来你真的很想做)。
【讨论】:
以上是关于没有抽象方法的抽象类的主要内容,如果未能解决你的问题,请参考以下文章