Boolan C++研发工程师课程的作业真是越往后越难了。学了两个月了,从小白走到现在,确实是提高了不少。笔芯侯捷老师。
/*题目:
设计一个Measurement计量单位类型,满足如下要求,
1. 当为距离单位,当构造米或者千米等不同距离单位的实例时,统一以米为基本单位,
实例调用description函数返回单位对应的meter类型(米类型)
2. 当为时间单位,当构造分钟或者秒为单位的实例时,统一以秒为基本单位,
实例调用description函数返回单位对应的second类型(秒类型)
3. 如果为除距离和时间的其他单位,都打印值即可。
提示
请使用Traits来完成该题,通过Traits获取不同计量单位的转换系数 和 基本单位。
用sprintf()函数将一个变量从int类型转换到字符串类型
*/
#include "stdafx.h"
#include<iostream>
#include <iterator>
//<sstream>常用于格式转换,他定义了三种类:istringstream、ostringstream和stringstream
//分别用来进行流的输入、输出和输入输出操作。
#include <sstream>
/*
定义函数模板来将一个任意的类型转换到特定的目标类型
template<class T>
void to_string(string & result,const T& t)
{
//创建一个流
ostringstream oss;
//把值传递如流中
oss<<t;
//使用str()成员函数来获取流内部缓冲的一份拷贝
//获取转换后的字符转并将其写入result
result=oss.str();
}
这样,你就可以轻松地将多种数值转换成字符串了:
to_string(s1,10.5);//double到string
to_string(s2,123);//int到string
to_string(s3,true);//bool到string
*/
using namespace std;
// 定义类型萃取机type_traits
template<typename T>
class type_traits
{
public :
//将T::type_traits的类型名命名为valueType
typedef typename T::type_traits valueType;
};
class meter {
private:
string m_str;
public:
//将meter类型改名为type_traits
typedef meter type_traits;
// 定义静态的转换系数
static int m_convertData;
//构造函数
meter(string str) :m_str(str) {}
//类型转换函数,为了在结尾加上单位
meter(double val, int con = 1)
{
/*
如果你打算在多次转换中使用同一个stringstream对象,记住再每次转换前要使用clear()方法;
在多次转换中重复使用同一个stringstream(而不是每次都创建一个新的对象)对象最大的好处在于效率。
stringstream对象的构造和析构函数通常是非常耗费CPU时间的。
stringstream的转换拥有类型安全和不会溢出的特性
*/
stringstream sstring;
// 输入double类型数值,输出string类型数值
//输出值为:距离*转换系数
sstring << val * con;
sstring >> m_str;
// 在输出值末尾加上基本单位
m_str = m_str + "m";
}
//拷贝构造
meter(meter& met)
{
//获取meter内的string数据
m_str = met.m_str;
}
// 重载运算符<<,作用:想让cout输出非标准库中的类型,就要重载<<来使其可以识别自定义的类别
friend ostream& operator<<(ostream& os, const meter& str)
{
//获取meter的私有string类型的数据m_str
os << str.getSting();
//将获取的数据返回
return os;
}
string getSting() const
{
//返回meter的私有数据m_str
return m_str;
}
};
class kilometer {
public :
//将meter的类型名命名为type_traits
typedef meter type_traits;
// 定义静态的转换系数
static int m_convertData;
};
class second {
private:
string m_str;
public:
//将second的类型名命名为type_traits
typedef second type_traits;
// 定义静态的转换系数
static int m_convertData;
//构造函数
second(string str) :m_str(str) {}
//类型转换
second(double val, int con = 1)
{
stringstream sstring;
//输入double类型值,输出string类型值
sstring << val * con;
sstring >> m_str;
// 在输出值末尾加上基本单位
m_str = m_str + "s";
}
//拷贝构造函数
second(second& met)
{
m_str = met.m_str;
}
// 重载运算符<<,为了可以sout自定义类型
friend ostream& operator<<(ostream& os, const second& str)
{
os << str.getSting();
return os;
}
string getSting() const
{
return m_str;
}
};
class minute {
public:
//将second的类型名命名为type_traits
typedef second type_traits;
// 定义静态的转换系数
static int m_convertData;
};
//传入参数的类型不确定,此时告知编译器传入的I是一个类型名
template<typename I>
class Measurement {
private:
double value;
public:
//构造函数
Measurement(double val) :value(val) {}
// 定义获取单位类型对应数值函数
//函数的返回值类型为type_traits<I>::valueType,即萃取出的传入的类型参数I的类型
typename type_traits<I>::valueType description()
{
//定义type_traits<I>::valueType的类名为valType
//kilometer的valueType为meter,minute的valueType为second
//因此kilometer类和minute类不需要写类型转换函数,也不需要重载<<
typedef typename type_traits<I>::valueType valType;
//获取不同计量单位的转换系数
int iconv = I::m_convertData;
//调用对应的自定义类中的类型转换函数
valType typeVal(value, iconv);
//返回带单位的string类型的字符串
return typeVal;
}
};
// 计量单位的泛化类型,因为传入的类名可能不是我们定义的类
template<>
//这里传入的是double类型,所以偏特化double
class Measurement<double>
{
private:
double value;
public:
//构造函数
Measurement(double val) :value(val) {}
//除距离和时间的其他单位,打印其值。
string description()
{
stringstream sstring;
string str;
sstring << value;
sstring >> str;
return str;
}
};
//为转化系数赋值
int meter::m_convertData = 1;
int kilometer::m_convertData = 1000;
int second::m_convertData = 1;
int minute::m_convertData = 60;
int main()
{
Measurement<meter> m1 = 20;
Measurement<kilometer> m2 = 11.2;
//创建拷贝构造函数
meter me = m1.description();
Measurement<second> m3 = 20;
Measurement<minute> m4 = 10;
Measurement<double> m5 = 10;
//想让cout输出非标准库中的类型,就要重载<<来使其可以识别自定义的类别
cout << me << endl;
cout << m2.description() << endl;
cout << m3.description() << endl;
cout << m4.description() << endl;
cout << m5.description() << endl;
return 0;
}