gpt4 book ai didi

c++ - 类具有相同的接口(interface),但参数类型不同

转载 作者:搜寻专家 更新时间:2023-10-31 00:26:23 25 4
gpt4 key购买 nike

我有一个 TypedNode 类来存储一些数据:

template <typename Type>
class TypedNode {
public:
TypedNode() {}
void SetNodeData(Type data) { data_ = data; }
Type GetNodeData() { return data_; }

private:
Type data_;
};

然后我就可以使用它了:

int main() {
TypedNode<int> int_node;
TypedNode<double> double_node;
TypedNode<Vector3d> vector3_node;

int_node.SetNodeData(1);
double_node.SetNodeData(2.3);
vector3_node.SetNodeData(Vector3d(4,5,6));;
}

但是我想定义一个函数来访问:

void Access(std::list<TypedNode> node_list) {
for (auto node : node_list) {
node.GetNodeData();
// if it is an integer, do one thing
// if it is a double, do another
}
}

列表需要一个具体的类,但我需要存储任何类型的节点。

一些我修改了Node的代码:

class NodeBase {
public:
NodeBase() {}
};

template <typename Type>
class TypedNode : NodeBase {
public:
TypedNode() {}
void SetNodeData(Type data) { data_ = data; }
Type GetNodeData() { return data_; }
private:
Type data_;
};

void Access(std::list<NodeBase> node_list) {
for (auto node : node_list) {
node.GetNodeData();
// if it is an integer, do one thing
// if it is a double, do another
}
}

但是Access()函数只能调用基类的方法。尽管每个派生类都有一个同名接口(interface) SetNodeData,但它们具有不同的类型。所以他们是不同的。它们不能覆盖基类中的同一个接口(interface)。

我能做什么?

============================================= ===============

这是我的解决方案:

#include <list>
enum NodeType {
kInt,
kDouble,
kVector3,
};

class NodeBase {
public:
NodeBase() {}

virtual int GetDataInt();
virtual double GetDataDouble();
virtual Vector3 GetDataVector3();
NodeType type() const { return type_; }

protected:
void set_type(NodeType type) { type_ = type; }

private:
NodeType type_;
};

class NodeInt : NodeBase {
public:
NodeInt() { set_type(kInt); }
int GetDataInt() override { return data_; }
double GetDataDouble() override { check(false) << "error"; }
Vector3 GetDataVector3() override { check(false) << "error"; }

private:
int data_;
};

class NodeDouble : NodeBase {
public:
NodeDouble() { set_type(kDouble); }
int GetDataInt() override { check(false) << "error"; }
double GetDataDouble() override { return data_; }
Vector3 GetDataVector3() override { check(false) << "error"; }

private:
double data_;
};

void Access(const std::list<NodeBase>& node_list) {
for (auto node : node_list) {
switch (node.type()) {
case kInt: {
int data = node.GetDataInt();
// do something about int
break;
}
case kDouble: {
double data = node.GetDataDouble();
// do something about double
break;
}
case kVector3: {
Vector3 data = node.GetDataVector3();
// do something about Vector3
break;
}
}
}
}

最佳答案

你的 TypedNode template 没有提供明显的值(value),它只是封装数据的 getter 和 setter,因此为了简单起见最好将其删除。您似乎需要的是一种可以是 int 的类型, doubleVector3d所以它们可以放在同一个容器中。为此有 std::variant在 C++17 中。编译器不合格的人可以使用 Boost.Variant这基本上是一样的,也适用于 C++98。

#include <variant>

struct Vector3d {int x, y, z;};
using Node = std::variant<int,double,Vector3d>;

当然,你可以有 std::variant<TypedNode<int>,TypedNode<double>,TypedNode<Vector3d>>当其中有一些重要功能时。发表TypedNode没有其他功能,但输入起来更臃肿。

要使用相同的接口(interface)访问变体,有几种方法。例如,它可以使用访问者来完成。这里有访客NodeOutput对于 ostream Node 中每种类型的输出.

#include <iostream>

struct NodeOutput {
std::ostream& os_;
NodeOutput(std::ostream& os) : os_{os} {}

void operator()(Vector3d const& v3)
{
os_ << "Vector3d (" << v3.x <<", "<< v3.y <<", "<< v3.z <<")\n";
}
void operator()(double const& d) {os_ << "Double " << d <<"\n";}
void operator()(int const& i) {os_ << "Int " << i <<"\n";}
};

使用这样的访问者我们可以写成operator<<对于 Node :

std::ostream& operator<< (std::ostream& os, Node const& v) {
std::visit(NodeOutput{os}, v);
return os;
}

尝试一下。 std::list是很少使用的容器,所以在这里它被替换为 std::vector为简单起见,但它与其他容器的工作方式类似。

#include<vector>

int main()
{
std::vector<Node> nodes;
nodes.emplace_back(42);
nodes.emplace_back(6.66);
nodes.emplace_back(Vector3d{3,2,1});

for (auto& n: nodes) {std::cout << n;}
}

输出:

Int 42
Double 6.66
Vector3d (3, 2, 1)

关于c++ - 类具有相同的接口(interface),但参数类型不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52678539/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com