c++ - Only know data type at run time. How to hide data details to other classes which use them
问题描述
Basically I have to populate objects based on an input text file with the following syntax:
float 4.55 24 2.1
int 4 6 9 0
float 5.1 6 6
//char 255 3 5
And then I need to make some sort of operations on them (for example a simple adition) there is no way to know beforehand which types of data there will be.
I can't store them all internally as double variables because space optimitation is important as well as not loosing precision.
I thought of doing something like:
class Base {
public:
virtual size_t size() = 0;
virtual void addValue () = 0;
virtual void getValue (int index) = 0;
};
class BaseFloat : public Base{
public:
vector<float> data;
void addValue (float d);
float getValue (int index);
size_t size();
}
class BaseInt : public Base{
public:
vector<int> data;
void addValue (int d);
Int getValue (int index);
size_t size();
}
/* other classes for each data type here*/
This doesn't work as each function has diferent return types or parameter needs;
Then I have one class which creates the correct object for each line.
The problem comes when I need to have other class which should work with any type of Base. I was thinking something like:
class OtherClass {
public:
void addValue(Base*, double);
}
OtherClass my_class; //whatever
Base* a = new BaseFloat ();
Base* b = new BaseInt();
my_class.addData(a, 5.56); //Uses BaseFloat::addValue
my_class.addData(b, 6); //Uses BaseInt::addValue
my_class.addData(b, 6.55); //Uses BaseInt::addValue
I was hoping I could do this without adding some sort of long if-else clause like:
void OtherClass::addDataHelper (Base* pointer)
if (subclass(pointer) == float)
//Do BaseFloat* a = pointer;
//Do a->addValue
else if ...
Any ideas?
解决方案
创建面向对象设计时,您需要定义基类的接口,因此所有派生类都可以在不更改签名的情况下覆盖虚函数。例如,对于读取数据,它可以这样实现:
class BaseData {
public:
virtual bool addValue( std::istream &in ) = 0;
};
class DataFloat : public BaseData {
virtual bool addValue( std::istream &in ) override
{
float v = 0;
if( not in >> v ) return false;
data_.push_back( v );
return true;
}
private:
std::vector<float> data_;
};
class Factory {
public:
std::unique_ptr<BaseData> create( const std::string &type );
};
std::vector<std::unique_ptr<BaseData>> parsing( std::istream &in, Factory &f )
{
std::vector<std::unique_ptr<BaseData>> v;
std::string str;
while( std::getline( in, str ) ) {
std::istringstream line( str );
std::string type;
if( not in >> type ) continue;
auto pbase = f.create( type );
while( pbase->addValue( in ) );
v.push_back( std::move( pbase ) );
}
return v;
}
当然这不是完整的代码,但应该足以说明这个想法。因此,对于您的操作,您需要做同样的事情 - 找到在基类中定义虚函数的方法,这样就可以在每个派生的函数中重新实现它而无需更改签名。您对每个类的方法void addValue( int data )
是否具有void addValue( float data )
正确的 OO 设计,并且将导致级联或类似方法。if
dynamic_cast
另一种解决方案是包含数据std::vector<std::variant<int,float,char,double>>
(列出所有必要的类型)并编写适当的访问者来进行数据插入和计算等。互联网上有很多关于如何正确执行此操作的材料,并且超出了此答案的范围他们在这里。
推荐阅读
- excel - 获取嵌入在用户窗体中的电子表格的最后一行
- javascript - 如何使用从?
- php - Laravel 中的路由问题 - 未找到错误
- mysql - 在 DATE 子句的 5 个表中加入或联合
- kubernetes - 通过代理汇集所有 Kubernetes 节点流量
- c# - 有没有办法在 Entity Framework Core 中映射临时表?
- angular - Angular 材质图标的问题
- r - 如何将数据子集到周围的行
- phabricator - 如何在 phabricator diff 上默认隐藏或折叠生成的文件?
- reactjs - 你如何以反应的方式从 mobx observable 中获取项目?