C++复习

模板函数

参数类型为变量的函数,参数的具体类型由编译器来确定
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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值