抽象类和虚拟构造函数的替代方案

abstract class and alternative to virtual constructor

本文关键字:方案 构造函数 虚拟 抽象类      更新时间:2023-10-16

让我有以下代码:

class Block{
private:
  data Data;
public:
  data getData();
  Block(arg3 Arg3, arg4 Arg4);
};

实际上,有几种构建块的方法,但是始终具有相同的成员数据和方法getData((,唯一的区别是如何构建块。换句话说,唯一的区别是构造函数...

,我可以将代码的一部分分解为每个构建过程,而是在抽象类中定义和声明getData的部分,如果C 中有一个虚拟构造函数,我可以为每个派生的派生都有不同的编写。班级对应于不同的建筑过程。

我对这种事情没有很多经验,所以我想知道是否有虚拟构造函数的替代方案?还是可能是进行这种分解的另一种方法?

ps:我知道https://isocpp.org/wiki/faq/virtual-funtions#virtual-ctors,但我想做的事情似乎很复杂,这似乎很普遍...我只想分配几个类之间的共享代码,这与构造函数以外的所有内容相对应。我想强迫与其他建筑过程相对应的新类以实现新的构造函数。

有关我特定情况的更多详细信息:

我有一种使用块的算法,它不取决于它们的构建过程,因此我使用模板参数实现了算法,以表示其建筑过程无关的块。但是我使用一些方法及其构造函数,因此我需要代表块的类具有相同类型的方法,并且使用相同的构造函数将它们用作我算法实现的模板参数。这就是为什么我想到抽象类,强迫新实现的类代表块以具有我实施的算法中所需的方法和构造函数的原因。可能是一个不好的设计模式,这就是为什么我被卡住...

编辑

感谢您到目前为止的回答。我试图有点通用,但我觉得它实际上太模糊了,即使我最后给出了细节。所以这是我想做的:我有一个矩阵类,如下所示

// 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);
}

live demo。

tl:dr,但是如果data对于所有Block S相同,您甚至不需要多个类但是只有多个构造函数。

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();
}