[英]c++ - abstract class and alternative to virtual constructor
假设我有以下代码:
class Block{
private:
data Data;
public:
data getData();
Block(arg3 Arg3, arg4 Arg4);
};
实际上,有多种方法来构建块,但是始终使用相同的成员Data和方法getData(),唯一的区别是如何构建块。 换句话说,唯一的区别是构造函数...
不用为每个构建过程编写不同的类,我可以分解代码的一部分,在抽象类中定义和声明getData,如果在c ++中存在诸如虚拟构造函数之类的东西,我可以为与之对应的每个派生类编写不同的内容不同的构建过程。
我对这种事情没有很多经验,所以我想知道是否有虚拟构造函数的替代方案? 还是做此分解的另一种方法?
PS:我知道https://isocpp.org/wiki/faq/virtual-functions#virtual-ctors,但是我想做的事情似乎很复杂,这似乎很普遍...我只是想分解共享几个类之间的代码,它对应于除构造函数以外的所有内容。 而且我想强制与其他构建过程相对应的新类来实现新的构造函数。
有关我的特定情况的更多详细信息:
我有一个使用块的算法,它不依赖于它们的构建过程,因此我已经使用模板参数实现了该算法,以无差别地代表其构建过程。 但是我使用了一些方法及其构造函数,因此,我需要代表块的类都具有所需的相同类型的方法和相同的构造函数,以将它们用作算法实现的模板参数。 这就是为什么我想到抽象类,迫使一个新实现的代表块的类在我实现的算法中具有我需要的方法和构造函数。 可能是一种不良的设计模式,这就是为什么我被困住了。
编辑
到目前为止,谢谢您的回答。 我试图变得有点泛泛,但是我觉得即使是最后给出的细节,它实际上也太模糊了。 所以这是我想做的:我有一个Matrix类,如下
// Matrix.hpp
template<typename GenericBlock> class Matrix{
std::vector<GenericBlock> blocks;
Matrix(arg1 Arg1, arg2 Arg2);
};
template<typename GenericBlock>
Matrix<GenericBlock>::Matrix(arg1 Arg1, arg2 Arg2){
// Do stuff
GenericBlock B(arg3 Arg3, arg4 Arg4);
B.getData();
}
块实际上是压缩的,并且存在几种压缩它们的方法,并且它不会改变Matrix
类中的任何内容。 为了避免为每种压缩技术编写矩阵类,我使用了您所看到的模板参数。 因此,我只需要为每种压缩技术编写一个类,但是它们必须具有相同的方法和构造函数参数,才能与Matrix
兼容。
这就是为什么我想到做一个抽象类,为每种压缩技术编写一个类。 在抽象类中,我将在Matrix
编写所需的所有内容,以便每个派生类都将与Matrix
兼容。 现在在我的示例中,我的问题是:我可以在抽象类中定义getData
,因为它总是相同的(例如, Data
可以是行数)。 派生类真正需要定义的唯一东西是构造函数。
一种解决方案是不具有抽象类,而可以使用受保护的构造函数。 但是,它不会强制新派生的类重新实现构造函数。 这就是为什么我被困住了。 但是我认为这个问题很普遍,足以引起其他人的兴趣。 那么在这种情况下,有没有虚拟构造函数的替代方法? (可能是一种工厂模式,但是对于这样一个常见问题似乎很复杂)如果没有,是否有更好的方法来实现一个矩阵类,该矩阵类的块可以以不同的方式构建,即其构造函数可以彼此不同,而有相同的数据和一些共同点?
PS:我对产生低阶矩阵的压缩技术很感兴趣,这就是为什么数据总是相同,而不是构建过程的原因。
到目前为止,您还不清楚为什么需要抽象类或虚拟构造函数。 每种构建模块的工厂功能都可以做到:
class Block {
Data data;
public:
Block(Data d) : data(std::move(d)) {}
Data getData();
};
Block createABlock() { return Block{Data{1.0, 2.0, 3.0}}; }
Block createBBlock() { return Block{Data{42.0, 3.14, 11.6}}; }
int main() {
auto b1 = createABlock();
auto b2 = createBBlock();
}
现场演示 。
也许这需要使用抽象工厂进行扩展,以便您可以在周围传递通用块工厂:
using BlockFactory = std::function<Block()>;
int main() {
BlockFactory f = createABlock;
auto b3 = f();
}
编辑 :关于您的编辑,您的建议工作正常 。 您不需要虚拟构造函数。 模板类型GenericBlock
只需满足模板定义的隐式接口。 它不需要从特定的基类派生(尽管可以这样做)。 唯一需要的是,它必须具有一个采用特定参数集和getData
方法的构造函数。 您拥有的是编译时静态多态性,虚函数是运行时动态多态性。
继承可以正常工作,但是正如我上面所说的,我很想使用某种工厂。 您可能不需要对整个Matrix
类进行模板化,因为只有构造函数需要工厂。 如果工厂在编译时已知,则可以将其作为模板参数传递:
class Matrix {
std::vector<Block> blocks;
public:
template<typename BlockFactory>
Matrix(BlockFactory f);
};
template<typename BlockFactory>
Matrix::Matrix(BlockFactory f){
// Do stuff...
Block B = f();
auto data = B.getData();
for (auto v : data)
std::cout << v << " ";
std::cout << "\n";
}
int main() {
Matrix ma(createABlock);
Matrix mb(createBBlock);
}
现场演示 。
TL:DR,但是如果所有Block
的data
都相同,则您甚至不需要多个类,而只需多个构造函数。
class Block
{
enum { type1, type2, type3 };
int type;
data Data;
public:
Block(int x)
: type(type1), Data(x) {}
Block(std::string const& str)
: type(type2), Data(str) {}
Block(data const*x)
: type(type3), Data(data) {}
/* ... */
};
template<class T>struct tag_t{constexpr tag_t(){}; usong type=T;};
template<class T>constexpr tag_t<T> tag{};
这使您可以将类型作为值传递。
struct BlockA{};
struct BlockB{};
class Block {
enum BlockType { typeA, typeB };;
BlockType type;
data Data;
public:
Block(tag_t<BlockA>, int x)
: type(typeA), Data(x) {}
Block(tag_t<BlockB>, int x)
: type(typeB), Data(2*x+7) {}
/* ... */
};
这些块都是相同的类型。 标签确定它们的构造方式。
除了虚拟构造函数之外,没有其他选择。 我知道很难接受,但这是事实。
无论如何,您不需要像虚拟构造函数那样存在的任何东西。
[..]唯一的区别是如何构建块。 换句话说,唯一的区别是构造函数...
如果唯一的区别在于构造函数,则只需使构造函数采用一个参数即可告知所需的块类型。 或者,您可以具有一些以不同方式构造块的函数:
struct Block {
private:
Block(){}
friend Block createWoodenBlock();
friend Block createStoneBlock();
};
Block createWoodenBlock(){ return Block(); }
Block createStoneBlock(){ return Block(); }
int main() {
Block woody = createWoodenBlock();
Block stony = createStoneBlock();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.