根据另一个成员参数将来自 class 的函数调用传递给其成员之一
Pass function call from a class to one of its members based on another member parameter
假设我有以下 class A
,它通过不同的函数调用和包装器传递。
class A{
std::vector<int> a;
public:
int getSize const {return a.size();}
int getVal(int i) const {return a[i];}
// other private and public members and functions
}
现在出于某种原因我需要相同的 class 但具有双向量。我无法将此 class 模板化,因为有许多我无法更改的函数签名。建议将 A
重命名为 A0
,将其模板化,创建包含 A0<int>
和 A0<double>
的新 A
,如下所示:
template <typename T>
class A0{
std::vector<T> a;
public:
int getSize const {return a.size();}
T getVal(int i) const {return a[i];}
// other private and public members and functions
}
class A{
// only one of the following will be initialized in the constructor and the other one will be null.
std::shared_ptr<A0<int>> iA;
std::shared_ptr<A0<double>> dA;
// also the following flag will be set in the constructor
bool isInt;
}
这是个问题:如果我想在以前访问、更改或只是绕过 class A
实例的代码的不同位置进行最小更改,应该是什么完毕?例如,在旧代码的不同部分考虑这个:
A x;
int n = x.getSize();
有没有一种方法可以保留旧代码,而无需在新 A
class 中实现方法 getSize()
,该方法将包含 if 条件语句和 return iA->getSize()
或 dA->getSize()
基于 isInt
?有没有聪明的方法来做到这一点?
对于使用旧 A
代码的不同部分(主要是绕过)实现最少修改的目标,是否还有其他建议?
}
std::variant
可能就是您所需要的。创建一个 buffer
class 并将所有容器操作转发给它。你的classA
没必要改太多,但你应该模仿buffer
里的std::vector<T>
,我实现了size()
和const subscript operator
.下面是基本演示。
#include <variant>
#include <vector>
#include <iostream>
struct store_as_int {};
struct store_as_double {};
class buffer {
public:
buffer( store_as_int ) : data { std::vector<int>{} } {
std::cout << "I am storing numbers as int" << std::endl;
}
buffer( store_as_double ) : data { std::vector<double>{} } {
std::cout << "I am storing numbers as double" << std::endl;
}
[[nodiscard]] std::size_t size() const noexcept {
std::size_t s;
std::visit( [ &s ]( auto&& arg ) {
s = arg.size();
} , data );
return s;
}
[[nodiscard]] double operator[]( std::size_t idx ) const {
double s;
std::visit( [ &s , idx ]( auto&& arg ) {
s = arg[ idx ];
} , data );
return s;
}
private:
std::variant< std::vector<int> , std::vector<double> > data;
};
class A{
buffer a;
public:
A() : a { store_as_int{} } {}
A( store_as_double ) : a { store_as_double {} } { }
int getSize() const { return a.size(); }
int getVal(int i) const { return a[i]; }
};
int main()
{
A x;
A y { store_as_double{} };
int n = x.getSize();
int t = x.getSize();
std::cout << n << std::endl;
std::cout << t << std::endl;
}
输出:
I am storing numbers as int
I am storing numbers as double
0
0
如果这只是关于传递对象(或对它的引用)而不实际使用对象的任何成员,那么您可以简单地使用 std::variant
:
using A = std::variant<A0<int>, A0<double>>;
在真正使用到成员的地方,用std::visit
判断类型并进行操作
如果仅通过引用传递,则将 A
设为 A0<T>
的空基数 class 也可以。然后,您可以使用 static_cast<A0<int>&>(...)
或 static_cast<A0<double>&>(...)
转换回真实类型以使用目标处的成员。但是,您必须 确保转换为所传递对象的实际类型,否则会出现未定义的行为。
另一种方法是 dynamic_cast
而不是 static_cast
,如果类型不匹配,它将抛出或 return 一个空指针。但这需要基础 class A
具有多态的虚拟方法。
假设我有以下 class A
,它通过不同的函数调用和包装器传递。
class A{
std::vector<int> a;
public:
int getSize const {return a.size();}
int getVal(int i) const {return a[i];}
// other private and public members and functions
}
现在出于某种原因我需要相同的 class 但具有双向量。我无法将此 class 模板化,因为有许多我无法更改的函数签名。建议将 A
重命名为 A0
,将其模板化,创建包含 A0<int>
和 A0<double>
的新 A
,如下所示:
template <typename T>
class A0{
std::vector<T> a;
public:
int getSize const {return a.size();}
T getVal(int i) const {return a[i];}
// other private and public members and functions
}
class A{
// only one of the following will be initialized in the constructor and the other one will be null.
std::shared_ptr<A0<int>> iA;
std::shared_ptr<A0<double>> dA;
// also the following flag will be set in the constructor
bool isInt;
}
这是个问题:如果我想在以前访问、更改或只是绕过 class A
实例的代码的不同位置进行最小更改,应该是什么完毕?例如,在旧代码的不同部分考虑这个:
A x;
int n = x.getSize();
有没有一种方法可以保留旧代码,而无需在新 A
class 中实现方法 getSize()
,该方法将包含 if 条件语句和 return iA->getSize()
或 dA->getSize()
基于 isInt
?有没有聪明的方法来做到这一点?
对于使用旧 A
代码的不同部分(主要是绕过)实现最少修改的目标,是否还有其他建议?
}
std::variant
可能就是您所需要的。创建一个 buffer
class 并将所有容器操作转发给它。你的classA
没必要改太多,但你应该模仿buffer
里的std::vector<T>
,我实现了size()
和const subscript operator
.下面是基本演示。
#include <variant>
#include <vector>
#include <iostream>
struct store_as_int {};
struct store_as_double {};
class buffer {
public:
buffer( store_as_int ) : data { std::vector<int>{} } {
std::cout << "I am storing numbers as int" << std::endl;
}
buffer( store_as_double ) : data { std::vector<double>{} } {
std::cout << "I am storing numbers as double" << std::endl;
}
[[nodiscard]] std::size_t size() const noexcept {
std::size_t s;
std::visit( [ &s ]( auto&& arg ) {
s = arg.size();
} , data );
return s;
}
[[nodiscard]] double operator[]( std::size_t idx ) const {
double s;
std::visit( [ &s , idx ]( auto&& arg ) {
s = arg[ idx ];
} , data );
return s;
}
private:
std::variant< std::vector<int> , std::vector<double> > data;
};
class A{
buffer a;
public:
A() : a { store_as_int{} } {}
A( store_as_double ) : a { store_as_double {} } { }
int getSize() const { return a.size(); }
int getVal(int i) const { return a[i]; }
};
int main()
{
A x;
A y { store_as_double{} };
int n = x.getSize();
int t = x.getSize();
std::cout << n << std::endl;
std::cout << t << std::endl;
}
输出:
I am storing numbers as int
I am storing numbers as double
0
0
如果这只是关于传递对象(或对它的引用)而不实际使用对象的任何成员,那么您可以简单地使用 std::variant
:
using A = std::variant<A0<int>, A0<double>>;
在真正使用到成员的地方,用std::visit
判断类型并进行操作
如果仅通过引用传递,则将 A
设为 A0<T>
的空基数 class 也可以。然后,您可以使用 static_cast<A0<int>&>(...)
或 static_cast<A0<double>&>(...)
转换回真实类型以使用目标处的成员。但是,您必须 确保转换为所传递对象的实际类型,否则会出现未定义的行为。
另一种方法是 dynamic_cast
而不是 static_cast
,如果类型不匹配,它将抛出或 return 一个空指针。但这需要基础 class A
具有多态的虚拟方法。