模板函数
参数类型为变量的函数,参数的具体类型由编译器来确定
template<class T>
T abc(T a, T b, T c)
{
return a + b + c;
}
此函数可以计算任何类型的a,b,c相加的值并将其返回
a,b,c必须为同一类型
void main()
{
cout<<abc(1, 2, 3)<<endl;
cout << abc('a','a', 'a') << endl;
cout << abc(0.1, 0.2, 0.3) << endl;
//cout << abc('a', 1, 0) << endl;
//cout << abc(1, 'a', 0) << endl;
system("pause");
}
被注释掉的两行无法运行,不同类型的不能进行运算
变量的类型由第一个输入的变量类型决定
类
声明
enum signType { plus, minus };
class currency//original
{
public:
currency(signType thesign = ::signType::plus, unsigned long theDollars = 0, unsigned int theCents = 0);
~currency() {}
void setValue(signType, unsigned long, unsigned int);
void setValue(double);
signType getSign() const { return sign; }
unsigned long getDollars() const { return dollars; }
unsigned int getCents() const { return cents; }
currency add(const currency&) const;
currency& increment(const currency&);
void output() const;
private:
signType sign;
unsigned long dollars;
unsigned int cents;
};
用于处理美元的类
用枚举定义plus和minus表示数目的正负
通过重载函数定义了一个使用符号、元、分赋值的函数,和一个直接使用小数赋值的函数
定义了用于输出元,输出分,相加,增加和输出的函数
数目的正负、元、分放于保护部分内
声明构造函数中,书上的代码直接就将thesign = plus
但实际这么做时visual studio指出plus不明确(is ambiguous)
因为我习惯性使用了using namespace std,而std中已有一个std::plus,造成编译器的不明确
所以要么指明是哪一个plus,写为::signType::plus或::plus,开头的::表示全局命名空间
要么不要直接使用整个std命名空间,仅将需要的部分单独导入,例如using std::cout,using std::cin
这段程序中使用了大量的const,关于const的使用将另写一篇文章总结
signType getSign() const { return sign; } 表明这个函数不会修改类内的任何变量
currency add( const currency& ) const; 第一个表明不会修改所调用的变量,第二个表明不会修改类内的任何变量
下面是具体的实现
构造函数
currency::currency(signType theSign,unsigned long theDollars, unsigned int theCents)
{
setValue(theSign, theDollars, theCents);
}
初始化数据成员
没有定义复制构造函数,将会使用缺省的复制构造函数,仅仅复制数据成员,对于这个类已经足够
对私有数据赋值
void currency::setValue(signType theSign, //original
unsigned long theDollars, unsigned int theCents)
{
if (theCents > 99)
throw illegalParameterValue("Cents should be < 100");
sign = theSign;
dollars = theDollars;
cents = theCents;
}
void currency::setValue(double theAmount) //original
{
if (theAmount < 0)
{
sign = ::minus; theAmount = -theAmount;
}
else sign = ::signType::plus;
dollars = (unsigned long)theAmount;
cents = (unsigned int)((theAmount + 0.001 - dollars) * 100);
}
使用符号、元、分的赋值函数中引入了一个自定义的异常illegalParameterValue,用于判断所给的分是不是超出范围
使用小数的赋值函数中在分的部分进行了+0.001,这是由于电脑表示小数时并不准确
例如,一个赋值是5.29的对象,其实际的值会比5.29小一点
如果去掉+0.001的部分,直接进行分的提取,得到的将会是28
两个对象的相加
currency currency::add(const currency& x) const //original
{
long a1, a2, a3;
currency result;
a1 = dollars * 100 + cents;
if (sign == ::minus)
a1 = -a1;
a2 = x.dollars * 100 + x.cents;
if (x.sign == ::signType::minus)
a2 = -a2;
a3 = a1 + a2;
if (a3 < 0)
{
result.sign = ::signType::minus; a3 = -a3;
}
else
result.sign = ::signType::plus;
result.dollars = a3 / 100;
result.cents = a3 - result.dollars * 100;
return result;
}
将被相加的两个对象的数据先都转换为整数
dollars表示的是调用add函数的对象的数据,x.dollars表示被引用的对象的数据
增加和输出
currency& currency::increment(const currency& x) //original
{
*this = add(x);
return *this;
}
void currency::output() const //original
{
if (sign == ::signType::minus)
cout << '-';
cout << '$' << dollars << '-';
if (cents < 10)
cout << '0';
cout << cents;
}
*this为调用increment函数的对象,即将自己与被引用的对象相加,然后返回给自己
自定义的异常类
class illegalParameterValue
{
public:
illegalParameterValue() :
message("Illegal parameter value") {}
illegalParameterValue(char* theMessage)
{
message = theMessage;
}
void outputMessage()
{
cout << message << endl;
}
private:
string message;
};
测试
void main()
{
currency g, h(::plus, 3, 50), i, j;
g.setValue(::minus, 2, 25);
i.setValue(-6.45);
j = h.add(g);
h.output();
cout << "+";
g.output();
cout << "=";
j.output();
cout << endl;
j = i.add(g).add(h);
j.output();
cout << endl;
j = i.increment(g).add(h);
j.output();
cout << endl;
cout << "Attempting to initialize with cents = 152" << endl;
try { i.setValue(::plus, 3, 152); }
catch (illegalParameterValue)
{
cout << "Caught thrown exception" << endl;
}
//i.setValue(::plus, 3, 152);
system("pause");
}
一切正常,尝试赋值152时会进入catch输出Caught thrown exception
如果不使用try和catch,直接进行i.setValue( ::plus, 3, 152 );,程序会提示unhandled exception然后崩溃
原因未知,异常这部分的了解太少
另一种描述方法
假设这个类被大量使用,为了提高效率可以将私有的数据成员改为一个long
由于用户仅通过公有部分的接口与类交互,修改私有部分不会影响程序的使用
并且可以通过对+和+=操作符进行重载,将add和increment操作变得很自然
类声明
class currency//using long, overloading operators
{
public:
currency(signType thesign = ::signType::plus, unsigned long theDollars = 0, unsigned int theCents = 0);
~currency() {}
void setValue(signType, unsigned long, unsigned int);
void setValue(double);
signType getSign() const
{
if (amount < 0) return ::minus;
else return ::plus;
}
unsigned long getDollars() const
{
if (amount < 0) return (-amount) / 100;
else return amount / 100;
}
unsigned int getCents() const
{
if (amount < 0) return -amount - getDollars() * 100;
else return amount - getDollars() * 100;
}
currency operator+(const currency&) const;
currency& operator+=(const currency& x)
{
amount += x.amount;
return *this;
}
void output(ostream&) const;
private:
long amount;
};
+重载,output及<<重载
currency currency::operator+(const currency& x) const
{
currency result;
result.amount = amount + x.amount;
return result;
}
void currency::output(ostream& out) const
{
long theAmount = amount;
if (theAmount < 0)
{
out << '-';
theAmount = -theAmount;
}
long dollars = theAmount / 100;
out << '$' << dollars << '.';
int cents = theAmount - dollars * 100;
if (cents < 10)
out << '0';
out << cents;
}
ostream& operator<<(ostream& out, const currency& x)
{
x.output(out);
return out;
}
因为数据为私有成员,只能被类内部的函数所访问
所以重载<<操作符后,还需要通过内部的output来实现输出
如果在currency内将ostream& operator<<声明为友元,就可以不需要output直接输出了
使用友元实现
class currency {
friend ostream& operator<<(ostream&, const currency&);
};
ostream operator<<(ostream& out, const currency& x)
{
long theAmount = x.amount;
if (theAmount < 0)
{
out << '-';
theAmount = -theAmount;
}
long dollars = theAmount / 100;
out << '$' << dollars << '.';
int cents = theAmount - dollars * 100;
if (cents < 10)
out << '0';
out << cents;
return out;
}
测试(通过output输出,未使用友元)
void main()
{
currency g, h(::plus, 3, 50), i, j;
g.setValue(::minus, 2, 25);
i.setValue(-6.45);
j = h + g;
cout << h << "+" << g << "=" << j << endl;
j = i + g + h;
cout << i << "+" << g << "+" << h << "=" << j << endl;
cout << "Increment" << i << "by" << g << "and then add" << h << endl;
j = (i += g) + h;;
cout << "Result is" << j << endl;;
cout << "Incremented object is" << i << endl;
cout << "Attempting to initialize with cents = 152" << endl;
try { i.setValue(::plus, 3, 152); }
catch (illegalParameterValue e)
{
cout << "Caught thrown exception" << endl;
e.outputMessage();
}
//i.setValue(::plus, 3, 152);
system("pause");
}
一切正常
同样,直接i.setValue(::plus, 3, 152); 时会出现unhandled exception
待解决
1、异常的定义以及抛出
2、ostream
3、&的用法
4、*this