C++复习

来源:互联网 发布:.club域名价值 编辑:程序博客网 时间:2024/05/18 14:44

模板函数

参数类型为变量的函数,参数的具体类型由编译器来确定
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,  //originalunsigned 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;}elseresult.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
0 0