Review cpp day05
Posted 达少Rising
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}
以上是关于Review cpp day05的主要内容,如果未能解决你的问题,请参考以下文章