c++:聚合、继承和指针
C++: aggregation, inheritance and pointers
这是一个关于给定问题在c++中特定OO实现的问题:
一个算法有几个变体,比如两个,它们都有一些通用的部分。这些算法(它们的实现,AlgImpl)接收启动选项。它们也接收输入的数据,然后逐个处理。提供启动选项的方式有很多(从文件、从网络、从用户输入),接收数据的方式也有很多(从文件、从设备)。对于不同的数据源,有一个通用的API,类似于选项。
架构应该允许使用任何可用的AlgImpl以及任何可用的选项和数据源。它还应该允许新的AlgImpl和可能的新类型的源选项和数据添加最小或不改变原始代码(说只有两个AlgImpl,两个选项源类型和两个数据源类型)。
下面是我对c++的看法,使用继承、聚合和指针。因为所有的AlgImpl都有一些共同的部分,所以很自然地将它们围绕一个基抽象类组织起来,所以(省略非必要的数据类型)我们有:
class BaseAlgorithm
{
... //Abstract class with common code
};
class SimpleAlgorithmImpl: public BaseAlgorithm
{
...
};
class OptimalAlgorithmImpl: public BaseAlgorithm
{
...
};
现在,选项和数据源分别具有相同的接口:
class BaseOptionsSource
{
public:
//Interface
virtual void GetOptions(Options& opts) = 0;
};
class FileOptionsSource: public BaseOptionsSource
{
void GetOptions(Options& opts);
...
};
class NetworkOptionsSource: public BaseOptionsSource
{
void GetOptions(Options& opts);
...
};
class BaseDataSource
{
public:
//Interface
virtual void GetDataChunk(DataChunk& chunk) = 0;
};
class FileDataSource: public BaseDataSource
{
void GetDataChunk(DataChunk& chunk);
...
};
class DeviceDataSource: public BaseDataSource
{
void GetDataChunk(DataChunk& chunk);
...
};
选项和数据源成为BaseAlgorithm:
的成员class BaseAlgorithm
{
public:
BaseAlgorithm(BaseDataSource* pDataSrc, BaseOptionsSource* pOptsSrc);
BaseDataSource* _pDataSrc;
BaseOptionsSource* _pOptsSrc;
};
BaseAlgorithm::BaseAlgorithm(BaseDataSource* pDataSrc, BaseOptionsSource* pOptsSrc):
_pDataSrc(pDataSrc), _pOptsSrc(pOptsSrc)
{
}
一个特定的算法对象可以这样创建:
DeviceDataSource dataSrc;
NetworkOptionsSource optsSrc;
SimpleAlgorithmImpl simpleAlg(&dataSrc, &optsSrc);
对于新的AlgImpl或新类型的源,它的类应该实现继承的方法。当然,必须有一个"if/else if/…"代码,在创建AlgImpl对象之前显式地选择使用的AlgImpl和源的集合。
源对象也可以在这种情况下被重用,只要AlgImpl对象不管理传递给它的源对象的分配/释放。
你认为在c++中这样做是正确的吗?或者,对于这种可互换的子功能实现,是否存在其他更简单、更灵活或不那么"无问题"的模式?在这种情况下使用指针是不可避免的吗?
看起来很合理。我认为指针是好的,如果你可以确信数据源和选项源是活的在算法的生命周期。我不认为指针是不可避免的。以下是一些其他选项(其中一些是c++ 11):
引用
最好是const引用。如果在构造函数中传递指针,并且不需要它们为空,则可能比指针更安全。
BaseAlgorithm(BaseDataSource& dataSrc,
BaseOptionsSource& optsSrc) :
dataSrc_(dataSrc),
optsSrc_(optsSrc) {}
共享智能指针
如果您不能确信数据源或选项源在算法的生命周期内是活的,请考虑传入std::shared_ptr
或std::weak_ptr
。如果你想让他们活着,使用std::shared_ptr
,如果你想知道他们是否活着,使用std::weak_ptr
。
BaseAlgorithm(std::weak_ptr<BaseDataSource> dataSrc,
std::weak_ptr<BaseOptionsSource> optsSrc) :
dataSrc_(dataSrc),
optsSrc(optsSrc) {}
水槽这取决于这些数据源,选项源和算法是如何创建和使用的,但如果算法获得数据源和/或选项源的所有权并通过unique_ptr传递,可能会使所有权更简单。
BaseAlgorithm(std::unique_ptr<BaseDataSource> dataSrc,
std::unique_ptr<BaseOptionsSource> optsSrc) :
dataSrc_(std::move(dataSrc)),
optsSrc(std::move(optsSrc)){}
一些小问题:我怀疑out参数是否是获取选项和数据块的最佳方式。即使对于像数据块这样大的东西,也不要害怕按值返回。任何现代编译器都会对副本进行优化,这使得调用代码更容易读写:
Options opts = optsSrc_->GetOptions(opts);
DataChunk data = dataSrc_->GetDataChunk(data);
你可能为了简化你的文章而错过了它们,但我想知道GetOptions
和/或GetDataChunk
是否可以成为const
?调用它们是否会对源代码进行更改?如果它们可以是const
,这意味着算法只需要一个指向源的const指针/引用,这可能会使查找错误稍微容易一些。您谈论重用源对象,如果算法可以对源对象进行更改,这可能不明智。例如,如果反复调用GetDataChunk会发生什么,每次都得到不同的块吗?如果您可以在不同的算法中使用相同的数据源,这可能会产生意想不到的后果。
最后,确保_pOptsSrc和_pDataSrc是protected
或private
而不是public。
- 关于C++中具有多重继承"this"指针的说明
- 共享指针继承,而不先显式强制转换
- 派生类是从基类继承 v 指针并仅使用它,还是也有自己的 v 指针?
- 使用智能指针附加的继承对象的深层复制
- 嵌套类、继承和C++中的共享指针
- 删除C++中的继承类指针数组
- 具有虚拟指针和继承的 CPP 类大小
- 钻石继承虚拟成员铸造与指针
- 当键是虚拟继承中涉及的基类指针时,对 std::unordered_map 项的访问崩溃
- 当依赖关系和依赖关系都是多态时,在哪个继承级别存储依赖关系指针?
- cppyy 继承包含智能指针的类
- 作为模板参数的成员函数指针在继承的成员函数上失败,如何以及为什么?
- 是否可以将成员作为指针继承
- C++14 不能调用从唯一指针继承的类的复制构造函数或运算符 =
- 是无限的Typedef函数指针继承
- 是否可以从 C++11 智能指针继承并覆盖相关运算符?
- 继承:使用从父指针继承的方法
- 使用智能指针继承的皮条
- 是覆盖返回类型所需的指针-继承
- 调用未从BaseClass指针继承的DerivedClass函数