Review cpp day05

回顾:
Review cpp day01
Review cpp day02
Review cpp day03
Review cpp day04

十五、this指针和常成员函数(常函数)

1、this指针

  • 类中的函数都隐藏一个该类类型的指针参数,名为this
    • 对于普通的成员函数,this指针指向调用函数的对象
    • 对于构造函数,this指向正在创建的对象

eg:

class A{
public:
	A(int i):m_i(i){}
	void print(void){
		cout << m_i << endl;
	}/*print编译后就会编程类似下面:*/
	void print(A* this){
		cout << this->m_i << endl;
	}
	int m_i;
};
int main(void){
	A a1(100);
	a a2(200);
	//A::print(&a1)
	a1.print();//100
	//A::print(&a2)
	a2.print();//200	
	return 0;
}

06this.cpp

#include <iostream>
using namespace std;

class User{
public:
	User(const string& name, int age)
		:m_name(name), m_age(age){
		cout << "构造函数this地址:" << this << endl;
	}
	void who(void){
		cout << m_name << ',' << m_age << endl;
	}
	/*
	void who(User* this){
		cout << this->m_name << ',' << this->m_age << endl;
	}
	*/
private:
	string m_name;
	int m_age;
};
int main(void){
	User u1("张飞",28);
	cout << "&u1=" << &u1 << endl;
	User u2("赵云",25);
	cout << "&u2=" << &u2 << endl;
	u1.who();//User::who(&u1);
	u2.who();//User::who(&u2);
	return 0;
}

2、需要显式使用this指针的场景

  • 区分作用域

07this.cpp

#include <iostream>
using namespace std;

class User{
public:
	//通过this指针区分成员变量和参数变量
	User(const string& m_name, int m_age){
		this->m_name = m_name;
		this->m_age = m_age;
	}
	void who(void){
		cout << m_name << ',' << m_age << endl;
	}
private:
	string m_name;
	int m_age;
};
int main(void){
	User u1("张飞",28);
	cout << "&u1=" << &u1 << endl;
	User u2("赵云",25);
	cout << "&u2=" << &u2 << endl;
	u1.who();//User::who(&u1);
	u2.who();//User::who(&u2);
	return 0;
}
  • 从成员函数返回调用对象自身

08this.cpp

#include <iostream>
using namespace std;

class Counter{
public:
	Counter(int num=0):m_num(num){}
	//Counter& add(Counter* this){
	Counter& add(void){
		//++this->m_num;
		++m_num;
		//this指向调用对象
		//*this就是调用对象自身
		return *this;//返回自引用
	}
	int m_num;
};
int main(void){
	Counter cn(1);
	//Counter::add(&cn);
	cn.add().add().add();
	cout << cn.m_num << endl;//4
	return 0;
}
  • 从类的内部销毁对象自身

09this.cpp

#include <iostream>
using namespace std;

class Counter{
public:
	Counter(int num=0):m_num(num){}
	//Counter& add(Counter* this){
	Counter& add(void){
		//++this->m_num;
		++m_num;
		//this指向调用对象
		//*this就是调用对象自身
		return *this;//返回自引用
	}
	void destory(void){
		cout << "this=" << this << endl;
	}
	int m_num;
};
int main(void){
	Counter* pc = new Counter(123);
	cout << pc->m_num << endl;//123
	cout << "pc=" << pc << endl;
	//delete pc;
	//pc = NULL;
	pc->destory;
	return 0;
}

2、常函数

  • 1)在一个成员函数参数表后面加上const修饰,这个成员函数就是常成员函数(常函数)。
    返回值 函数名(形参表) const {//函数体}
  • 2)常函数中的this指针是一个常指针,不能在常函数中修改成员变量的值。
    注: 被mutable关键字修饰的成员变量可以在常函数中被修改。

09constFunc.cpp

#include <iostream>
using namespace std;

class A{
public:
	A(int data):m_data(data){}
	/*正常情况下不能再常函数中修改m_data,但是如
	*果m_data被mutable修饰就可以修改
	*/
	void print(void)const{//常函数
		cout << m_data << endl;
		//cout << m_data++ << endl;//防止出现修改成员函数的操作
	}
	/*void print(const A* this){//常函数
	*	//cout << m_data++ << endl;
	*}
	*/
	mutable int m_data;
};
int main(void){
	A a(100);
	a.print();//100
	return 0;
}
  • 3)非-常对象既可以调用非-常函数,也可以调用常函数;但是常对象只能调用常函数,不能调用非-常函数

10constFunc.cpp

#include <iostream>
using namespace std;
class A{
public:
	//void func1(const A* this)
	void func1(void)const{
		cout << "常函数" << endl;
		//在一个常函数里调用一个普通成员函数是错误的
		//func2();
	}
	//void func2(A* this)
	void func2(void){
		cout << "非-常函数" << endl;
		//在普通成员函数中调用常函数是可以的
		func1();
	}
};
int main(void){
	A a;//非-常对象
	a.func1();//A::func1(&a), A*
	a.func2();//ok
	const A a2 = a;//常对象
	a2.func1();//A::func1(&a2), const A*
	a2.func2();//error

	const A& ra = a;//常引用
	ra.func1()
	//ra.func2();//error
	
	const A* pa = &a;//常指针
	pa->func1();
	//pa->func2();//error

	return 0;
}
  • 4)函数名和形参表相同的成员函数,其常版本和非-常版本可以构成有效的重载,常对象调用常版本,非-常对象调用非-常版本。

11constFunc.cpp

#include <iostream>
using namespace std;

class A{
public:
	//void func(const A* this)
	void func(void)const{
		cout << "常版本" << endl;
	//void func(A* this)
	void func(void){
		cout << "非-常版本" << endl;
};
int main(void){
	A a1;
	a1.func();//非-常版本
	const A a2 = a1;
	a2.func();//常版本
	return 0;
}

十六、析构函数(Destructor)

1、语法

class 类名{
	~类名(void){
		//负责清理对象创建时的动态资源
	}
};
  • 1)函数名必须是“~类名”
  • 2)没有返回类型,也没有参数,所以也无法重载

2、当对象销毁时,该类的析构函数会自动被执行

  • 1)栈对象当离开作用域时,其析构函数被作用域终止的右花括号"}"调用
  • 2)堆对象的析构函数被delete操作符调用

12destructor.cpp

#include <iostream>
using namespace std;

class Integer{
public:
	Integer(int data = 0):m_data(new int(data)){
		//m_data = new int(data);
	}
	void print(void)const{
		cout << *m_data << endl;
	}
	~Integer(void){
		cout << "析构函数" << endl;
		delete m_data;
	}
private:
	int* m_data;
};
int main(void){
	if(1){
		Integer i(100);
		i.print();//100
		cout << "test1" << endl;

		Integer* pi = new Integer(200);
		pi->print();//200
		delete pi;//-->调用析构函数
		cout << "test3" << endl;
	}//-->调用析构函数
	cout << "test2" << endl;
	return 0;
}
100
test1
200
析构函数
test3
析构函数
test2

3、如果一个类没有定义析构函数,那么系统会为该类提供一个缺省的析构函数

  • 对于基本类型的成员,什么也不做;
  • 对于类类型的成员 变量(成员子对象),调用相应类的析构函数。

13destructor.cpp

#include <iostream>
using namespace std;

class A{
public:
	A(void){
		cout << "A::A()" << endl;
	}
	~A(void){
		cout << "A::~A()" << endl;
	}
};
class B{
public:
	B(void){
		cout << "B::B()" << endl;
	}
	~B(void){
		cout << "B::~B()" << endl;
	}
	A m_a;//类类型的成员变量
};
int main(void){
	B b;
	return 0;
}
A::A()
B::B()
B::~B()
A::~A()

4、对象创建和销毁的过程

  • 1)创建

    • 分配内存
    • 构造成员子对象(按声明顺序)
    • 执行构造函数代码
  • 2)销毁

    • 执行析构函数代码
    • 析构成员子对象(按声明逆序)
    • 释放内存
  • 扩展练习V3.0:实现企业员工管理系统

    • 需求:修改和完善员工类
      • 1)将打印员工信息改成常函数
      • 2)构造函数初始化操作改成初始化表
      • 3)在构造函数中打开一个文件,以工号命名,保存员工信息
    • 提示:
class Employee{
public:
	Employee(...):...{
		工号(int)-->工号(char*)//sprintf
		file = fopen(工号,"w");
		saveInfo();//保存员工信息
	}
	~Employee(void){
		fclose(file);
	}
private:
	FILE* file;
};

Employee.h

#include <iostream>
using namespace std;

class Employee{
public:
	Employee(int id, const string& name, double salary);
	Employee(void);
	~Employee(void);
	void printInfo(void)const;
	void calSalary(void);
	void setId(int id);
	void setName(const string& name);
	void setSalary(double salary);
	void saveInfo(void)  const;
private:
	int m_id;//工号
	string m_name;//姓名
	double m_salary;//工资
	FILE* file;//保存信息文件
};

Employee.cpp

#include "Employee.h"

Employee::Employee(int id, const string& name, double salary)
		:m_id(id), m_name(name), m_salary(salary){
	if(m_id>0){
		char filename[20] = {0};
		sprintf(filename, "%d", m_id);
		file = fopen(filename, "w");
		if(file == NULL){
			cout << "file open error" << endl;
		}
	}
	saveInfo();
}
Employee::~Employee(void){
	fclose(file);	
}
void Employee::printInfo(void)const{
	cout << "姓名:" << m_name << endl;
	cout << "工号:" << m_id << endl;
	cout << "基础工资:" << m_salary << endl; 
}
void Employee::calSalary(void){
	cout << "请输入出勤天数:";
	int days;
	cin >> days;
	double basic = m_salary * (days/23.0);
	double merit = basic / 2;
	cout << "总工资为:" << (basic + merit) << endl;
}
void Employee::setid(int id){
	if(id < 10000){
		cout << "无效的工号" << endl;
	}
	else{
		m_id = id;
	}
}
void Employee::setName(const string& name){
	if(name.size() > 20){
		cout << "无效的姓名" << endl;
	}
	else{
		m_name = name;
	}
}
void Employee::setSalary(double){
	if(salary < 0){
		cout << "无效工资" << endl;
	}
	else{
		m_salary = salary;
	}
}
void Employee::saveInfo(void)const{
	fseek(file, 0, SEEK_SET);
	fprintf(file, "%d %s %g", m_id, m_name.c_str(), m_salary);
}

main.cpp

#include "Employee.h"
int main(void){
	Employee emp(10001, "张三", 6600);
	emp.printInfo();
	emp.calSalary();
	
	Employee* pemp = new Employee(10002, "李四", 8800);
	pemp->printInfo();
	pemp->calSalary();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值