C++基于子类类型的动态模板参数
C++ Dynamic template parameter based on subclass type
我目前正在第一个C++项目中工作,试图通过经验学习语言。这很有挑战性,但到目前为止,我已经通过自己和互联网的帮助解决了大多数问题
然而,最近我遇到了一些问题,我根本找不到令人满意的解决方案,所以我想听听更有经验的程序员的意见。
问题如下:
一方面,我有一个抽象的BaseShape
类,从中继承了几个具体的类,如Triangle
、Circle
、Rectangle
等
RenderCommand<Shape>
类,它对每个混凝土形状都有专门的定义BaseShape
指针我现在的问题是,从这些BaseShape
指针创建专用RenderCommand
实例的最佳方式是什么?我目前正在考虑动态选角,或者尝试一些虚拟方法的多态性,但感觉都不对。
编辑
目前,我已经确定了一个可行的解决方案,但我知道它可能没有遵循几个最佳实践,因此我仍然愿意接受其他建议。
为了稍微澄清一下,我还添加了一些伪代码来解释类定义的布局。
RenderCommands.h
struct BaseRenderCommand
{
virtual execute() = 0;
... // contains stuff on cameras and other render options
}
template<class Shape>
struct RenderCommand : public BaseRenderCommand
{
RenderCommand(Shape *shape) {...};
virtual execute();
...
}
Shapes.h
struct BaseShape
{
... // Typical shape info like center position
}
struct Triangle : public BaseShape
{
...
}
struct Circle : public BaseShape
{
...
}
struct Rectangle : public BaseShape
{
...
}
以下是一种可能解决此问题的方法。我将把您从运行时构造(polymorphism
(转移到编译时构造std::variant
。
在没有任何代码的情况下,我不得不在这里做大量的假设。还要注意,我包括了基本Shape
class
,但在我提供的示例中完全没有必要。
#include <vector>
#include <variant>
template<class... Ts> struct overload : Ts... { using Ts::operator()...; };
template<class... Ts> overload(Ts...) -> overload<Ts...>;
struct Shape {
virtual ~Shape() = default;
};
struct Square : public Shape {};
struct Triangle : public Shape {};
struct Circle : public Shape {};
template<typename T>
struct RenderCommand {
void render(const T&) {}
};
/* Your RenderCommand specializations here. */
using Shapes = std::variant<Square, Triangle, Circle>;
int main()
{
std::vector<Shapes> shapes {Square{}, Triangle{}, Circle{}};
for (const auto& shape : shapes)
{
std::visit(overload{
[](const Square& s) { RenderCommand<Square>{}.render(s); },
[](const Triangle& t) { RenderCommand<Triangle>{}.render(t); },
[](const Circle& c) { RenderCommand<Circle>{}.render(c); }
}, shape);
}
}
我继续并决定构建类似于WBuck给出的第一个建议的东西。我忘记在原始答案中包含的一条信息是,RenderCommand<Shape>
还继承了一个具有纯虚拟execute()
函数的抽象基类BaseRenderCommand
。
我决定的解决方案是这样的:
RenderCommands.h
struct BaseRenderCommand
{
virtual execute() = 0;
...
}
template<class Shape>
struct RenderCommand : public BaseRenderCommand
{
RenderCommand(Shape *shape) {...};
virtual execute();
...
}
RenderCommands.cpp
#include "RenderCommands.h"
#include "Shapes.h"
void RenderCommand<Triangle>::execute()
{
...
}
void RenderCommand<Circle>::execute()
{
...
}
void RenderCommand<Rectangle>::execute()
{
...
}
Shapes.h
#include RenderCommands.h
struct BaseShape
{
virtual BaseRenderCommand *create_cmd() = 0;
...
}
struct Triangle : public BaseShape
{
virtual BaseRenderCommand *create_cmd();
...
}
struct Circle : public BaseShape
{
virtual BaseRenderCommand *create_cmd();
...
}
struct Rectangle : public BaseShape
{
virtual BaseRenderCommand *create_cmd();
...
}
Shapes.cpp
#include "Shapes.h"
BaseRenderCommand *Triangle::create_cmd()
{
return RenderCommand<Triangle>(this);
}
BaseRenderCommand *Circle::create_cmd()
{
return RenderCommand<Circle>(this);
}
BaseRenderCommand *Rectangle::create_cmd()
{
return RenderCommand<Rectangle>(this);
}
main.cpp
#include <vector>
#include "RenderCommands.h"
#include "Shapes.h"
std::vector<BaseShape*> shapes = new std::vector<BaseShape*>();
std::vector<BaseRenderCommand*> renderCmds = new std::vector<BaseRenderCommand*>();
...
for (auto shape : shapes)
{
renderCmds.push_back(shape->create_cmd())
}
您似乎对命令模式有一些误解。使用命令模式并不意味着您需要使用class Command
或Command::Execute()
之类的东西。您所需要的只是一个std::function
或一个lambda。
你不应该有Shape::create_cmd()
。相反,命令应该是Shape
类中的一个可赋值变量,这样您就可以向它添加不同的命令,并通过Shape::execute()
执行它们。
这里有一些你可以尝试的东西:
形状:
struct Shape
{
std::string name;
std::function<void(Shape*)> command = [](Shape*){};
void execute() { command(this); }
};
struct Circle: Shape {
explicit Circle(double radius)
: Shape{"circle"}
, radius{radius}
{}
double radius;
void setCommand(std::function<void(Circle*)> const& command) {
this->command = [command](Shape* shape){command(static_cast<Circle*>(shape));};
}
};
struct Triangle: Shape {
Triangle(double base, double height)
: Shape{"triangle"}
, base{base}
, height{height}
{}
double base;
double height;
void setCommand(std::function<void(Triangle*)> const& command) {
this->command = [command](Shape* shape){command(static_cast<Triangle*>(shape));};
}
};
命令:
template<std::derived_from<Shape> T>
void render(T*);
template<>
void render(Circle* circle)
{
std::cout << circle->name << " is round!n";
}
template<>
void render(Triangle* triangle)
{
std::cout << triangle->name << " is sharp!n";
}
template<std::derived_from<Shape> T>
void print_area(T*);
template<>
void print_area(Circle* circle)
{
std::cout << "Circle area: " << circle->radius * circle->radius * 3.14 << 'n';
}
template<>
void print_area(Triangle* triangle)
{
std::cout << "Triangle area: " << triangle->height * triangle->base / 2 << 'n';
}
int main()
{
Circle circle(2);
Triangle triangle(3, 10);
auto vec = std::vector<Shape*>{&circle, &triangle};
std::cout << "Nothing happens here:n";
for (const auto& shape : vec)
{
shape->execute();
}
circle.setCommand(render<Circle>);
triangle.setCommand(render<Triangle>);
std::cout << "nRender:n";
for (const auto& shape : vec)
{
shape->execute();
}
circle.setCommand(print_area<Circle>);
triangle.setCommand(print_area<Triangle>);
std::cout << "nPrint area:n";
for (const auto& shape : vec)
{
shape->execute();
}
}
- C++基于输入参数的动态代码生成
- 我可以动态创建新地图并作为函数参数传递吗?
- 无法将动态创建的对象数组从 qml 发送到 c++ 作为方法参数
- 如果您为类的一个对象动态分配内存作为参数,会发生什么
- 将数组动态分配到具有指针参数的函数中
- 如何动态加载和调用具有特定于库的类型作为函数参数的符号
- 传递给函数的模板化参数的动态大小数组
- 如何在 C++11 中创建具有命令行参数大小的动态数组?
- 如何使用每个对象的单个构造函数参数动态分配C++对象数组?
- 动态构建模板参数包
- 在为 Java 编译动态链接文件时,我应该选择哪些 g++ 参数
- 动态创建和扩展STD ::元组为参数包
- 如何在不动态铸造的情况下使用派生的参数
- 如何动态执行具有任意参数类型的函数指针
- 在C 中解开包装的类似Python的动态参数
- 将动态创建的数组作为参数传递
- 如何使用一些参数初始化动态分配的数组中的对象
- 使用动态参数提升内存池
- 使用动态参数创建线程
- boost::绑定动态参数