背景
我有一个抽象类,比如
class IConverter{
public:
virtual void DoConvertion() = 0;
};
将会有许多具体的类实现 DoConvertion 方法。
class TextConverter : public IConverter{
public:
virtual void DoConvertion(){
// my code goes here
}
};
class ImageConverter : public IConverter{
public:
virtual void DoConvertion(){
// my code goes here
}
};
会有很多这样的具体实现。我创建了一个头文件,例如 CharacterConverter.h ,其中包含抽象类 IConverter 。
问题
由于我的具体类只是实现 DoConvertion 方法,是否需要为每个具体类创建单独的头文件?我的意思是需要为所有具体类创建 ImageConverter.h , TextConverter.h 等等吗?所有这些头文件将包含相同的代码,如 IConverter 抽象类。
有什么想法吗?
答案 0 :(得分:8)
不是必需的。这基本上是一个判断电话。
如果每个类的实现都很简单,你可以将它们全部放在一个.h和一个.cpp
中如果实现时间稍长,那么为每个实现使用单独的.h和.cpp文件可能更简洁。
为每个类使用不同的.h / .cpp的一些优点:
答案 1 :(得分:1)
你可能会两种方式得到答案。
我会说,对于任何简单的转换器,将它们全部放在单个.h / .cpp对中就足够了,将每一个分成一对就太过分了。我认为在这种情况下,维护大量文件与在一个文件中维护一堆方法的权衡是值得的。
复杂的转换可能值得拥有自己的文件对。
答案 2 :(得分:1)
您需要具体类的定义来创建对象,因此您需要将这些定义放在某个.h文件中。你把它们放在哪个文件取决于你。
答案 3 :(得分:1)
最好的答案是什么更容易阅读。一个很长的源文件对你和其他程序员来说很难跟上。另一方面,许多微小的(半屏幕完整)源文件同样糟糕。
答案 4 :(得分:1)
根据设计的其余部分,你可能会考虑的是一个工厂,你的抽象类有一个静态方法(或多个静态方法,取决于你如何实现它),构造适当的子类并将其作为IConverter *。这样,您可以只在头文件中公开抽象定义,并在单个.cpp文件中包含所有具体的类定义和实现以及超类实现。如果您的子类很大,这会变得有点笨拙,但是如果类较小,则会减少您必须管理的文件数。
但是,正如其他人所指出的那样,这最终是一种判断力。唯一的性能问题与编译有关;更多的cpp文件可能需要(稍微)更长的时间来编译,更多的头文件可能会增加依赖性分析。但是并不要求每个头文件都有匹配的cpp和反之亦然。
根据评论,我建议使用这样的结构:
IConverter.h ==> IConverter的定义
Converters.h ==>所有子类的定义
IConverter.cpp ==>包括IConverter.h和Converters.h,包含IConverter抽象功能的实现(静态工厂方法和任何可继承的功能)
TextConvter.cpp,ImagerConverter.cpp等等==>每个子类的单独cpp文件,每个子文件包含IConverter.h和Converters.h
这使您只能在使用工厂和通用功能的任何客户端中包含IConverter.h。将所有其他定义放在单个标题中,如果它们基本相同,则可以合并。单独的cpp文件允许您利用Brian提到的编译器优势。您可以如上所述内联头文件中的子类定义,但这并不能真正为您带来任何好处。在内联等优化方面,您的编译器通常比您更聪明。
答案 5 :(得分:1)
创建接口类的一个要点是,客户端可以依赖于抽象接口而不是具体实现,然后您可以自由地更改实现而不会影响客户端。
将具体声明放在与接口声明相同的头文件中会使其失败,所以现在如果更改具体类的实现细节,则客户端需要重新编译。
答案 6 :(得分:1)
使用工厂或函数指针可能会更好。
但是,一种特别令人讨厌的方式是使用宏来声明你的具体类。例如:
在IConverter.h的底部包含以下宏
#define DECLARE_CONVERTER_CLASS(CLASS_NAME) \
class CLASS_NAME : public IConverter\
{ \
public: \
CLASS_NAME() {} \
virtual void DoConversion(); \
}; \
然后在MyConverter1.cpp
DECLARE_CONVERTER_CLASS(MyConverter1)
virtual void MyConverter1::DoConversion()
{
...
}
Yuck: - )