创建一个函数,该函数返回具有现有类继承的不同类型
Create a function that returns different types with existing class inheritance
所以有以下现有的类:
class Data {};
class String_data : public Data {
string m_data;
public:
string str() { return m_data; }
};
class Integer_data : public Data {
int m_data;
public:
int value() { return m_data; }
};
我正在尝试做一些类似重载函数的事情,但对于基类:
string get_data(String_data *data) {
return data->str();
}
int get_data(Integer_data *data) {
return data->value();
}
问题是这些对象作为基类的对象指针存储在容器中,如下所示:
std::map<string, Data*> data_list;
data_list.emplace( std::pair<string, Data*>("first", new String_data()) );
data_list.emplace( std::pair<string, Data*>("second", new Integer_data()) );
所以,我试图让它像这样工作:
string first_data = get_value(data_list["first"]);
int second_data = get_value(data_list["second"]);
编辑:对不起,这必须很长。我想让问题保持简单,但除非我陈述全部意图,否则它不会完全起作用。
data_list中的一些项目非常恒定,我想创建一种简单的方法来扩展项目列表,而无需创建包装类并为每个类提供单独的访问方法,如下所示:
class DataListWrapper {
map<string, Data*> m_data_list;
public:
string get_house() { return ((String_data*)m_data_list["house"])->str(); }
int get_loan() { return ((Integer_data*)m_data_list["loan"])->value(); }
// etc...
};
为了确保这些,开发人员不会意外地错误键入字符串键,我为编译器创建了全局常量以检查编译时。
#ifndef STRING_CONSTANTS
#define STRING_CONSTANTS
constexpr char c_house[] = "house";
constexpr char c_loan[] = "loan";
#endif
因此,目前我们这样做:
string house = ((String_data*)m_data_list["house"])->str();
int loan = ((Integer_data*)m_data_list["loan"])->value();
call_me(house, loan);
但是我想扩展列表,并通过执行非常简单和轻松的事情来轻松获得值,例如:
string house = get_value(m_data_list[c_house]);
int loan = get_value(m_data_list[c_loan]);
call_me(house, loan)
编辑:从某种意义上说,我想在没有类型转换的情况下做到这一点,因为它变得非常冗长,并且使人们远离代码试图对所有类型转换所做的事情。
您可以使用std::variant
轻松实现这一点,它保留了告诉使用哪种类型的元数据。因此,您可以删除空基类:
using Data = std::variant<String_data, Integer_data>;
std::map<string, Data> data_list;
data_list.emplace("first", String_data{});
data_list.emplace("second", Integer_data{});
然后使用允许您检查基础数据的访问者:
auto get_data(String_data const& data) -> std::string {
return data.str();
}
auto get_data(Integer_data const& data) -> int {
return data.value();
}
std::visit(
[](auto& data) { auto value = get_data(data); },
data_list["first"]
);
std::visit(
[](auto& data) { auto value = get_data(data); },
data_list["second"]
);
但是,如果要保留类层次结构,则始终可以使用虚拟多态性实现自己的访问者:
struct Visitor {
virtual void operator()(int const&) const = 0;
virtual void operator()(std::string const&) const = 0;
};
struct PrintVisitor : Visitor {
void operator()(int const& value) const override {
std::cout << value;
}
void operator()(std::string const& value) const override {
std::cout << value;
}
};
struct Data {
virtual void visit(Visitor const&) const = 0;
};
struct String_data : Data {
void visit(Visitor const& v) const override {
v(m_data);
}
private:
std::string m_data;
};
struct Integer_data : Data {
void visit(Visitor const& v) const override {
v(m_data);
}
private:
int m_data;
};
然后使用它:
data_list["first"]->visit(PrintVisitor{});
data_list["second"]->visit(PrintVisitor{});
当然,如果您已经知道地图中元素的类型,则可以使用static_cast
.但它需要您有足够的上下文来提前知道将有哪种类型:
string first_data = get_value(static_cast<String_data*>((data_list["first"]));
int second_data = get_value(static_cast<Integer_data*>((data_list["second"]));
call_me(first_data, second_data);
我建议不要使用dynamic_cast
.当您要使用动态转换时,最好使用变体。以这种方式向下抛弃它意味着你知道你将要处理的类型数量,并且会像变体一样约束层次结构,但以一种更微妙和容易出错的方式。
由于您在问题中添加了更多详细信息,因此问题更清晰。
我的解决方案是不直接使用字符串,而是使用某种标识符来封装如何强制转换以及如何获取值。
struct house_data_t {
static constexpr auto index = "house";
using type = String_data;
} inline constexpr house_data{};
struct loan_data_t {
static constexpr auto index = "loan";
using type = Integer_data;
} inline constexpr loan_data{};
然后创建一个使用此元数据的函数:
std::string house = get_value(house_data, data_list);
int loan = get_value(loan_data, data_list);
get_value
函数可以这样实现:
auto get_data(String_data* data) -> std::string {
return data->str();
}
auto get_data(Integer_data* data) -> int {
return data->value();
}
using data_list_t = std::map<std::string_view, std::unique_ptr<Data>>;
template<typename data_t, typename data_type_t = typename data_t::type>
auto get_value(data_t data, data_list_t& data_list) -> decltype(get_data(std::declval<data_type_t*>())) {
return get_data(static_cast<data_type_t*>(data_list[data.index].get()));
}
现场示例
- C++虚函数继承
- 名称隐藏对静态函数继承的实例使用
- C++ std::vector 中的虚拟析构函数继承
- 具有相同名称的类的构造函数继承
- 多复制构造函数继承中的惊人行为
- CRTP 和复制/移动赋值/构造函数继承
- 复制构造函数继承动态分配的数组
- 谷神星求解器成本函数继承错误:模板可能不是虚拟的
- 无法从 c++ 中的构造函数继承
- 在构造函数继承中使用默认构造函数
- 如何定义从虚拟函数继承的静态函数
- 调用超类函数继承 c++
- 构造函数继承和直接成员初始化
- c++ 不明确的双非虚函数继承
- C++ - 使用私有参数的构造函数继承
- 通过可变参数模板进行C++11构造函数继承
- 使用模板进行函数继承
- C++11构造函数继承和不带参数的构造函数
- 函数继承问题
- C++11 - 构造函数继承