- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
假设我有以下代码:
class Block{
private:
data Data;
public:
data getData();
Block(arg3 Arg3, arg4 Arg4);
};
其实,构建区 block 的方式有很多种,但总是使用相同的成员Data和方法getData(),唯一的区别是如何构建区 block 。换句话说,唯一的区别是构造函数......
我可以分解部分代码,在抽象类中定义和声明 getData,而不是为每个构建过程编写不同的类,如果在 c++ 中有虚拟构造函数之类的东西,我可以为每个派生的代码编写不同的代码类对应不同的构建过程。
我对这类事情没有太多经验,所以我想知道是否有虚拟构造函数的替代方案?或者可能是进行这种因式分解的不同方法?
PS:我知道https://isocpp.org/wiki/faq/virtual-functions#virtual-ctors但是关于我想做的事情似乎很复杂,这似乎很常见......我只想分解几个类之间的共享代码,这对应于除构造函数之外的所有内容。而且我想强制对应于其他构建过程的新类实现一个新的构造函数。
关于我的具体情况的更多细节:
我有一个使用 block 的算法,它不依赖于它们的构建过程,所以我使用模板参数实现了该算法,以表示一个与其构建过程无关的 block 。但是我使用了一些方法及其构造函数,所以我需要代表 block 的类都具有我需要的相同类型的方法和相同的构造函数以将它们用作我的算法实现的模板参数。这就是为什么我想到抽象类,强制一个新实现的类代表 block 具有我实现的算法中需要的方法和构造函数。可能这是一个糟糕的设计模式,这就是我被困的原因......
编辑
感谢您到目前为止的回答。我试着说得有点笼统,但我觉得它实际上太模糊了,即使我最后给出了细节。所以这就是我想做的:我有一个 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();
}
block 实际上是压缩的,有几种压缩它们的方法,它不会改变 Matrix
类中的任何内容。为了避免为每种压缩技术编写一个矩阵类,我使用了一个模板参数,如您所见。所以我只需要为每种压缩技术编写一个类,但它们必须具有相同的方法和构造函数参数才能与 Matrix
兼容。
这就是为什么我想到做一个抽象类,为每个压缩技术编写一个类。在抽象类中,我会在 Matrix
中编写所有需要的内容,以便每个派生类都与 Matrix
兼容。我的示例中现在的问题是:我可以在抽象类中定义 getData
,因为它总是相同的(例如,Data
可以是行数)。派生类唯一真正需要定义的是构造函数。
一个解决方案是不使用抽象类,而是使用 protected 构造函数。但它并不强制新派生类重新实现构造函数。这就是为什么我被困住了。但我认为这个问题很普遍,足以引起其他人的兴趣。那么在这种情况下是否有替代虚拟构造函数的方法? (可能是工厂模式,但对于这样一个常见问题来说似乎很复杂)如果没有,是否有更好的方法来实现一个矩阵类,其 block 可以以不同的方式构建,即其构造函数可以彼此不同,而有相同的数据和一些共同的方法?
PS:我对产生低秩矩阵的压缩技术很感兴趣,这就是为什么数据总是相同的,但构建过程却不同。
最佳答案
从您目前分享的内容来看,您不清楚为什么需要抽象类或虚拟构造函数。用于构建 block 的每种方式的工厂函数将执行以下操作:
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();
}
也许这需要用一个抽象工厂来扩展,这样你就可以传递一个通用的 block 工厂:
using BlockFactory = std::function<Block()>;
int main() {
BlockFactory f = createABlock;
auto b3 = f();
}
编辑:关于您的编辑,您的建议works fine .您不需要虚拟构造函数。模板类型 GenericBlock
只需满足模板定义的隐式接口(interface)即可。它不需要派生自特定的基类(尽管它可以)。唯一需要的是它必须有一个构造函数,该构造函数采用一组特定的参数和一个 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);
}
关于c++ - 抽象类和虚拟构造函数的替代方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44249971/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!