类和对象的知识

构造函数

分为有参构造函数和无参构造函数 其中带默认值的构造函数也可以看成无参构造函数

一个类的声明中必须有构造函数 否则类无法成功生成

#include <iostream>	
using namespace std;

class Clock {
public:
	Clock(int newH,int newM,int newS);//有参构造函数
   Clock(){
	   hour=0;minute=0;second=0;
   }//无参构造函数
   //带默认值的构造函数同时也可以被看作无参构造函数
   //在声明构造函数的时候确定了默认值
	void setTime(int newH, int newM, int newS);
	void showTime();
private:
	int hour, minute, second;
};


//Clock::Clock(int newH, int newM, int newS): hour(newH), minute(newM), second(newS) { }
Clock::Clock(int newH, int newM, int newS)
{
	hour=newH; minute=newM; second=newS;
}
void Clock::setTime(int newH, int newM, int newS) {
	hour = newH;
	minute = newM;
	second = newS;
}

inline void Clock::showTime() {
	cout << hour << ":" << minute << ":" << second << endl;
}


int main() {
  Clock c1(8,10,0); //此处将自动调用有参构造函数
  Clock c2;        //此处将自动调用无参构造函数
  c1.showTime();
  c2.showTime();
	return 0;
}
include<iostream>
using namespace std;

class Clock {
public:
    // 修正:移除默认参数,只在声明或定义一个地方提供默认参数
    Clock(int newH, int newM, int newS);
    Clock(); // 修正:添加默认构造函数声明
    void settime(int newH, int newM, int newS);
    void showtime(); // 修正:修正函数声明,移除多余的 void
private:
    int hour, minute, second;
};

// 添加默认构造函数定义

Clock::Clock() {
    hour = 0;
    minute = 0;
    second = 0;
}/*与之前把默认值添加在函数声明结构的代码比较 显然把所有函数拿出声明部分 单独定义会使代码可读性更高 且更有逻辑 易于维护*/



// 构造函数的定义
Clock::Clock(int newH, int newM, int newS) {
    hour = newH;
    minute = newM;
    second = newS;
}

// 修正:修正函数定义,移除多余的 void
void Clock::showtime() {
    cout << hour << ":" << minute << ":" << second << endl;
}

int main() {
    // 修正:移除多余的括号
    Clock c1(8, 30, 30);
    Clock c2; // 修正:使用默认构造函数创建 c2
    c1.showtime(); // 修正:调用函数需要加括号
    c2.showtime();

    return 0;
}

*:复制构造函数

#include<iostream>
using namespace std;

Point(const Point& p);
class Point {   //Point 类的定义
public:
	Point(int xx = 0, int yy = 0) { x = xx; y = yy; }    //构造函数,内联
	Point(const Point& p); //复制构造函数
	void setX(int xx) { x = xx; }
	void setY(int yy) { y = yy; }
	int getX() const { return x; } //常函数(第5章)
	int getY() const { return y; } //常函数(第5章)
private:
	int x, y; //私有数据
};
//成员函数的实现
Point::Point(const Point& p) {
	x = p.x;
	y = p.y;
	cout << "Calling the copy constructor " << endl;
}
//形参为Point类对象的函数
void fun1(Point p) {
	cout << p.getX() << endl;
}
//返回值为Point类对象的函数
Point fun2() {//函数的定义是Point所以函数的返回值也是对象
	Point a(1, 2);//创建一个对象 并利用构造函数进行初始化
	return a;//返回对象
}

//主程序
int main() {
	Point a(4, 5);	//第一个对象A
	Point b = a;	//情况一,用A初始化B。第一次调用复制构造函数
	cout << b.getX() << endl;
	fun1(b);	//情况二,对象b作为fun1的实参。第二次调用复制构造函数
	b = fun2();	//情况三,函数的返回值是类对象,函数返回时调用复制构造函数
	cout << b.getX() << endl;
	return 0;
}

整个程序运行的过程如下:

1. **定义 Point 类:** 定义了一个 `Point` 类,包括构造函数、复制构造函数、成员函数以及私有数据成员 `x` 和 `y`。

2. **创建对象:** 在 `main` 函数中创建了两个 `Point` 对象,`a` 和 `b`。对象 `b` 的初始化使用了对象 `a`,这时调用了复制构造函数。

3. **调用函数 fun1:** 调用了 `fun1` 函数,将对象 `b` 作为参数传递给函数。在这个过程中,又一次调用了复制构造函数。

4. **调用函数 fun2:** 调用了 `fun2` 函数,该函数返回一个 `Point` 对象。将函数返回值赋给对象 `b` 时,同样调用了复制构造函数。

5. **输出结果:** 在每个涉及到复制构造函数调用的情况下,程序输出了相应的信息,包括对象的坐标值和复制构造函数的调用情况。

总体而言,该程序主要用于演示对象的初始化、函数参数传递以及函数返回值时复制构造函数的调用过程。


析构函数

#include <iostream>
using namespace std;
class DEMO_CLASS {
public:
	DEMO_CLASS(int i);
	~DEMO_CLASS();
};

DEMO_CLASS::DEMO_CLASS(int i)//定义构造函数
{
	cout << "Initial value is " << i << "\n";
}

DEMO_CLASS::~DEMO_CLASS()//定义析构函数
{
	cout << "Goodbye!\n";
}
int main()
{
	DEMO_CLASS obj(30);// 声明一个对象
	cout << "This is the end of main().\n";
	return 0;
}

类组合

1.原则:不仅要负责对本类中的基本类型成员数据赋初值,也要对对象成员初始化。

2.声明形式: 类名::类名(对象成员所需的形参,本类成员形参)        :对象1(参数),对象2(参数),......

3.首先对构造函数初始化列表中列出的成员(包括基本类型成员和对象成员)进行初始化,初始化次序是成员在类体中定义的次序。

成员对象构造函数调用顺序:按对象成员的声明顺序,先声明者先构造。 初始化列表中未出现的成员对象,调用用默认构造函数(即无形参的)初始化 处理完初始化列表之后,再执行构造函数的函数体。

析构函数调用的次序相反。

对象成员的构造函数的调用顺序:取决于这些对象成员的说明顺序,与它们在初始化列表中给出的顺序无关。

当建立X类的对象时,先调用对象成员的构造函数,再执行X类的构造函数。    

     先客人(按照客人出场顺序),后自己

析构函数的调用顺序是先执行X类的析构函数,然后再调用对象成员的析构函数。          

先自己,后客人

例1:object and container

#include <iostream>
using namespace std;

class Object {
private:
    int val;

public:
    Object();
    Object(int i);
    ~Object();
};

Object::Object() {
    val = 0;
    cout << "Default constructor for Object" << endl;
}

Object::Object(int i) {
    val = i;
    cout << "Constructor for Object " << val << endl;
}

Object::~Object() {
    cout << "Destructor for Object " << val << endl;
}

class Container {
private:
    Object one;
    Object two;
    int data;

public:
    Container();
    Container(int i, int j, int k);
    ~Container();
};

Container::Container() {
    data = 0;
    cout << "Default constructor for Container" << endl;
}

Container::Container(int i, int j, int k) : two(i), one(j) {
    data = k;
    cout << "Constructor for Container" << endl;
}

Container::~Container() {
    cout << "Destructor for Container" << endl;
}

int main() {
    Container anObj(5, 6, 10);
    return 0;
}

结果:

在container类中 声明了两个object的变量 分别为one two 且声明的顺序与后续构造函数调用的顺序一致

在main函数中 我们把one初始化为6 two初始化为5 虽然在container构造函数定义中 初始化列表中 先two后one 但C++采用声明时的顺序 即先one后two 所以输出为Constructor for object 6 然后是5最后是自己的构造函数

析构函数的调用顺序与此正好相反 所以先是container自己的析构函数 然后是two 最后是one

例2:point and line

#include <iostream>
#include <cmath>
using namespace std;
class Point {	//Point类定义
public:
	Point(int xx = 0, int yy = 0) {
		x = xx;
		y = yy;
	}
	Point(Point& p);
	int getX() { return x; }
	int getY() { return y; }
private:
	int x, y;
};

/*point类有一个构造函数 用于初始化x和y 并有一个默认参数为0的构造函数*/
/*复制构造函数用于复制另一个point对象的值*/
Point::Point(Point& p) {	//复制构造函数的实现
	x = p.x;
	y = p.y;
	cout << "Calling the copy constructor of Point" << endl;
}


//类的组合
class Line {	//Line类的定义
public:	//外部接口
	Line(Point xp1, Point xp2);
	Line(Line& l);
	double getLen() { return len; }
private:	//私有数据成员
	Point p1, p2;	//Point类的对象p1,p2
	double len;
};
/*line类包含两个point对象p1和p2 以及一个表示线段长度的len*/
//组合类的构造函数
Line::Line(Point xp1, Point xp2) : p1(xp1), p2(xp2) {
	cout << "Calling constructor of Line" << endl;
	double x = static_cast<double>(p1.getX() - p2.getX());
	double y = static_cast<double>(p1.getY() - p2.getY());
	len = sqrt(x * x + y * y);
}
/*使用初始化列表初始化p1和p2 计算线段的长度并存储在‘len’中*/
Line::Line(Line& l) : p1(l.p1), p2(l.p2) {//组合类的复制构造函数
	cout << "Calling the copy constructor of Line" << endl;
	len = l.len;
}
//主函数
int main() {
	Point myp1(1, 1), myp2(4, 5);	//建立Point类的对象
	Line line(myp1, myp2);	//建立Line类的对象
	Line line2(line);	//利用复制构造函数建立一个新对象
	cout << "The length of the line is: ";
	cout << line.getLen() << endl;
	cout << "The length of the line2 is: ";
	cout << line2.getLen() << endl;
	return 0;
}

结果:


 


知识的综合运用

一个人可以由多个活期储蓄账户,一个活期账户包括账号(id),余额(banlance),年利率(rate)等信息,还包括显示账户信息(show),存款(deposit),取款(withdraw),结算利息(settle)等操作。为此,设计一个类SavingsAccount,将id,balance, rate作为数据成员,将show, deposit, withdraw, settle均作为成员函数。

#include <iostream>
#include <cmath>
using namespace std;
class SavingsAccount { //储蓄账户类
private:
	int id;				//账号
	double balance;		//余额
	double rate;		//存款的年利率
	int lastDate;		//上次变更余额的时期
	double accumulation;	//余额按日累加之和

	//记录一笔帐,date为日期,amount为金额,desc为说明
	void record(int date, double amount);
	//获得到指定日期为止的存款金额按日累积值
	double accumulate(int date) const {
		return accumulation + balance * (date - lastDate);
	}
public:
	//构造函数
	SavingsAccount(int date, int id, double rate);
	int getId() { return id; }
	double getBalance() { return balance; }
	double getRate() { return rate; }

	//存入现金
	void deposit(int date, double amount);
	//取出现金
	void withdraw(int date, double amount);
	//结算利息,每年1月1日调用一次该函数
	void settle(int date);
	//显示账户信息
	void show();
};
//SavingsAccount类相关成员函数的实现
SavingsAccount::SavingsAccount(int date, int id, double rate)
	: id(id), balance(0), rate(rate), lastDate(date), accumulation(0) {
	cout << date << "\t#" << id << " is created" << endl;
}
void SavingsAccount::record(int date, double amount) {
	accumulation = accumulate(date);
	lastDate = date;
	amount = floor(amount * 100 + 0.5) / 100; //保留小数点后两位
	balance += amount;
	cout << date << "\t#" << id << "\t" << amount << "\t" << balance << endl;
}
void SavingsAccount::deposit(int date, double amount) {
	record(date, amount);
}
void SavingsAccount::withdraw(int date, double amount) {
	if (amount > getBalance())
		cout << "Error: not enough money" << endl;
	else
		record(date, -amount);
}

void SavingsAccount::settle(int date) {
	double interest = accumulate(date) * rate / 365;	//计算年息
	if (interest != 0)
		record(date, interest);
	accumulation = 0;
}

void SavingsAccount::show() {
	cout << "#" << id << "\tBalance: " << balance;
}
int main() {
	//建立几个账户
	SavingsAccount sa0(1, 21325302, 0.015);
	SavingsAccount sa1(1, 58320212, 0.015);
	//几笔账目
	sa0.deposit(5, 5000);
	sa1.deposit(25, 10000);
	sa0.deposit(45, 5500);
	sa1.withdraw(60, 4000);
	//开户后第90天到了银行的计息日,结算所有账户的年息
	sa0.settle(90);
	sa1.settle(90);
	//输出各个账户信息
	sa0.show();	cout << endl;
	sa1.show();	cout << endl;
	return 0;
}

这段代码实现了一个简单的储蓄账户管理系统,包括储蓄账户类 `SavingsAccount` 和主函数的交互。

主要功能包括:
- 储蓄账户的创建与初始化。
- 记录存款和取款操作,实时更新余额。
- 在每年的1月1日结算账户年息。
- 显示账户信息。

下面是对程序的详细解释:

1. **SavingsAccount 类:**
   - 私有成员包括账号 `id`、余额 `balance`、年利率 `rate`、上次变更余额的时期 `lastDate`、余额按日累加之和 `accumulation`。
   - 构造函数初始化账户信息,并输出创建账户的信息。
   - `record` 函数记录一笔账目,包括日期、金额、说明,并更新余额。
   - `deposit` 函数存入现金,调用 `record` 函数记录存款。
   - `withdraw` 函数取出现金,调用 `record` 函数记录取款。
   - `settle` 函数在每年的1月1日结算账户年息,调用 `record` 函数记录利息。
   - `show` 函数用于显示账户信息。

2. **主函数:**
   - 创建两个储蓄账户对象 `sa0` 和 `sa1`。
   - 进行一系列的存款和取款操作。
   - 在开户后的第90天,调用 `settle` 函数结算所有账户的年息。
   - 输出各个账户的信息。

程序的运行流程包括账户的创建、存款和取款记录、年息的结算,最后显示各个账户的信息。这样的系统能够方便地管理储蓄账户并进行相关操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值