C++核心知识回顾(自定义数据类型)

2023-06-05,,

复习C++

自定义数据类型最灵活的方式就是使用C++的类结构

现在定义一个货币类型Currency:

enum signType{PLUS,MINUS};

class Currency {
public:
Currency(signType theSign = 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;
};

类的成员声明有两部分: public 和 private,分别代表公有和私有,公有部分所声明的是来操作类对象(或实例)的成员函数(方法),它们对类的用户是可见的,是用户与类对象进行交互的唯一手段。私有部分声明的是用户不可见的数据成员和成员函数,公有部分的地一个成员函数与类名相同

名称与类名相同的成员函数为构造函数,指明了第一个创建类对象的方法,无返回值,以~为前缀的函数是析构函数

set前缀的函数供给用户为类对象赋值,get前缀的函数返回调用对象的相应数据成员,关键字const指明这些函数不会改变调用对象的值,这种函数称为常量函数

成员函数add将调用对象的货币值与参数对象的货币值相加,然后返回相加后的结果,因为该成员函数不会改变调用对象的值,所以是一个常量函数

成员函数increment将参数对象的货币值加到调用对象上,改变了调用对象的值,所以不是一个常量函数

实现构造函数, 调用setValue函数进行赋值:

Currency::Currency(signType theSign, unsigned long theDollars, unsigned int theCents) {
setValue(theSign,theDollars,theCents);
}

对于setValue函数有两个重载,第一个成员函数setValue首先验证参数值的合法性,只有参数值合法,才能用来给调用对象的私有数据成员赋值,如果参数不合法,就抛出一个类型为illegalParameterValue的异常

第二个成员函数setValue不验证参数值的合法性,仅使用小数点后面头两个数字,对于形如d1.d2d3的数,用计算机表示可能就是不精确的,比如应计算机表示数值5.29,实际存储的值可能比5.29略小,如果像下面这样抽取美分的值可能要出错:

cents = (unsigned int)((theAmount - dollars) * 100);

因为(theAmount-dollars)*100要比29稍微小一点,当程序将其转化为一个整数时,赋给cents的值是28而不是29,解决这个问题的方法是给theAmount加上0.001,这时,只要d1.d2d3用计算机表示后与实际值相比不少于0.001或不多于0.009,结果是正确的

void Currency::setValue(signType theSign, unsigned long theDollars, unsigned int theCents) {
if (theCents > 99) {
throw illegalParametrValue("Cents should be < 100");
}
sign = theSign;
dollars = theDollars;
cents = theCents;
} void Currency::setValue(double theAmount) {
if (theAmount < 0) {
sign = MINUS;
theAmount = -theAmount;
} else {
sign = PLUS;
}
dollars = (unsigned long) theAmount;
cents = (unsigned int) ((theAmount + 0.001 - dollars) * 100);
}

接下来的add的代码:

Currency Currency::add(const Currency &x) const {
long a1,a2,a3;
Currency result;
a1 = dollars * 100 + cents;
if (sign == MINUS) a1 = -a1;
a2 = x.dollars * 100 + x.cents;
if (x.sign == MINUS) a2 = -a2;
a3 = a1 + a2;
if (a3 < 0) {
result.sign = MINUS;
a3 = -a3;
} else {
result.sign = PLUS;
}
result.dollars = a3/100;
result.cents = a3 - result.dollars * 100; return result;
}

首先要将相加的两个对象转化为整数,result是局部对象,作为返回值必须被复制到调用环境中,此处是值返回

下面是increment和output的代码:

Currency& Currency::increment(const Currency &x) {
*this = add(x);
return *this;
} void Currency::output() const {
if (sign == MINUS) cout << '-';
cout << '$' << dollars << '.';
if (cents < 10) cout << '0';
cout << cents;
}

保留关键字this指向调用对象,*this即调用对象,这里调用add函数,将x与调用对象相加,然后将相加的结果赋值给this,这个对象不是局部对象,当函数结束时,空间不会自动释放,所以返回引用

另一种写法:

enum signType{PLUS,MINUS};

class Currency {
public:
Currency(signType theSign = PLUS,
unsigned long theDollars = 0,
unsigned int theCents = 0);
~Currency() {}
void setValue(signType,unsigned long,unsigned int);
void setValue(double);
signType getSign() const { return amount < 0? MINUS:PLUS; }
unsigned long getDollars() const { return (amount < 0? -amount:amount) / 100; }
unsigned int getCents() const { return (amount < 0? -amount:amount)-getDollars()*100; }
Currency add(const Currency&) const;
Currency& increment(const Currency&);
void output() const;
Currency operator+(const Currency&) const;
Currency operator+=(const Currency& x) { amount += x.amount}
private:
long amount;
}; Currency::Currency(signType theSign, unsigned long theDollars, unsigned int theCents) {
setValue(theSign,theDollars,theCents);
} void Currency::setValue(signType theSign, unsigned long theDollars, unsigned int theCents) {
if (theCents > 99) {
throw illegalParametrValue("Cents should be < 100");
}
amount = theDollars * 100 + theCents;
if (theSign == MINUS) amount -= amount;
} void Currency::setValue(double theAmount) {
if (theAmount < 0) {
amount = (long) ((theAmount - 0.001) * 100);
} else {
amount = (long) ((theAmount + 0.001) * 100);
}
} Currency Currency::add(const Currency &x) const {
Currency y;
y.amount = amount + x.amount;
return y;
}

操作符重载

借助操作符重载,使用+和+=替代add和increment,成员函数output用一个输出流的名字作为参数

class Currency {
public:
Currency(signType theSign = PLUS,
unsigned long theDollars = 0,
unsigned int theCents = 0);
~Currency() {}
void setValue(signType,unsigned long,unsigned int);
void setValue(double);
signType getSign() const { return amount < 0? MINUS:PLUS; }
unsigned long getDollars() const { return (amount < 0? -amount:amount) / 100; }
unsigned int getCents() const { return (amount < 0? -amount:amount)-getDollars()*100; }
Currency add(const Currency&) const;
Currency& increment(const Currency&);
void output(ostream &out) const;
Currency operator+(const Currency&) const;
Currency operator+=(const Currency& x) { amount += x.amount; return *this; }
private:
long amount;
}; 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;
} Currency Currency::operator+(const Currency &x) const {
Currency result;
result.amount = amount + x.amount;
return result;
}

友元

可以赋予别的类和函数直接访问该类私有成员的权利,可将这些类和函数声明为该类的友元

friend ostream& operator<<(ostream&, const Currency&);

将ostream& operator<<声明为currency类的友元,就可以直接访问currency类的所有成员,这时就不用另外定义成员函数output

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;
}

C++核心知识回顾(自定义数据类型)的相关教程结束。

《C++核心知识回顾(自定义数据类型).doc》

下载本文的Word格式文档,以方便收藏与打印。