C++核心知识回顾(自定义数据类型)
复习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++核心知识回顾(自定义数据类型)的更多相关文章
- Docker 核心知识回顾
Docker 核心知识回顾 最近公司为了提高项目治理能力.提升开发效率,将之前的CICD项目扩展成devops进行项目管理.开发人员需要对自己的负责的项目进行流水线的部署,包括写Dockerfile ...
- Python 编程核心知识体系-基础|数据类型|控制流(一)
Python知识体系思维导图: 基础知识 数据类型 1.序列 2.字符串 3.列表和元组 4.字典和集合 循环 & 判断
- python---基础知识回顾(六)网络编程
python---基础知识回顾(十)进程和线程(进程) python---基础知识回顾(十)进程和线程(多线程) python---基础知识回顾(十)进程和线程(自定义线程池) 一:Socket (一 ...
- php核心知识要点
Php:脚本语言,网站建设,服务器端运行 PHP定义:一种服务器端的 HTML 脚本/编程语言,是一种简单的.面向对象的.解释型的.健壮的.安全的.性能非常之高的.独立于架构的.可移植的.动态的脚本语 ...
- Java基础知识回顾之七 ----- 总结篇
前言 在之前Java基础知识回顾中,我们回顾了基础数据类型.修饰符和String.三大特性.集合.多线程和IO.本篇文章则对之前学过的知识进行总结.除了简单的复习之外,还会增加一些相应的理解. 基础数 ...
- Cookie详解、ASP.NET核心知识(7)
无状态的http协议 1.回顾http协议 Http协议是请求响应式的,有请求才有响应,是无状态的,不会记得上次和网页“发生了什么”. 关于http协议的这种特点,黑兔在前面的这三篇博文中进行了详细的 ...
- Java基础知识回顾(一):字符串小结
Java的基础知识回顾之字符串 一.引言 很多人喜欢在前面加入赘述,事实上去技术网站找相关的内容的一般都应当已经对相应知识有一定了解,因此我不再过多赘述字符串到底是什么东西,在官网中已经写得很明确了, ...
- [C#] C# 知识回顾 - 你真的懂异常(Exception)吗?
你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...
- [C#] C# 知识回顾 - 学会使用异常
学会使用异常 在 C# 中,程序中在运行时出现的错误,会不断在程序中进行传播,这种机制称为“异常”. 异常通常由错误的代码引发,并由能够更正错误的代码进行 catch. 异常可由 .NET 的 CLR ...
- [.NET] C# 知识回顾 - Event 事件
C# 知识回顾 - Event 事件 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6060297.html 序 昨天,通过<C# 知识回顾 - ...
随机推荐
- Redis工具类 单机+集群
package com.irdstudio.basic.framework.redis.redisutil; import org.springframework.dao.DataAccessExce ...
- little bug
1 python script can be run in shell console while not in calling shell scripts wfile = codecs.open(n ...
- List转Map处理
List对象装一个Map<String,String> 在Java8中新增了stream流的操作,对于代码书写更为简便,而且更容易看的懂 List<Unit> unitList ...
- Cplex解决JSP问题
我的上一篇博客Cplex解决FSP问题 - 加油,陌生人! - 博客园 (cnblogs.com)用Cplex完成了FSP的建模,这篇文章主要是解决JSP问题(车间调度问题). JSP问题:n个工件, ...
- BlenderGIS记录
blender GIS 的插件名:"3Dview:blenderGIS" 具体使用方法看文档. 选择地图时选择bing地图会快一点.如果能挂梯子可以选择google地图 shift ...
- git 拉取远端别的分支的代码,并创建本地分支
创建本地分支 new_dev, 并且拉取远端new_dev的代码到本地new_devgit checkout -b new_dev origin/new_dev
- loadrunner入门(关联)
左右边界:提取第一个id web_reg_save_param_ex( "ParamName=Id", "LB=//OK[ ...
- 微信小程序中注册页面设计
.wxml <text>姓名</text> <input placeholder="请输入姓名" bindinput="getname&qu ...
- 使用Git进行版本控制,不同的项目怎么设置不同的提交用户名和邮箱呢?
1.全局设置用户名和邮箱 因为平时除了开发公司项目还会写自己的项目或者去维护开源项目,一般情况下,公司会要求提交代码时使用自己的真名或者拼音和公司邮箱,以前就只会设置全局用户名或邮箱如下 git co ...
- ansible批量采集、批量互信、批量复制、分发文件
一.先说一下用ansible批量采集机器信息的实现办法: 1.先把要采集的机器信息的IP添加到主节点机器的/etc/ansible/hosts里面: 2.在/etc/ansible/hosts里面添加 ...