文章目录
this指针和常成员函数
this指针
代码示例
常成员函数(常函数)
代码示例
析构函数(Destructor)
代码示例
拷贝构造和拷贝赋值
代码示例
this指针和常成员函数
this指针
- 类中的构造函数和成员函数都隐藏了一个该类类型的指针参数,名为this;在构造函数或者成员访问类中的其它成员时,本质都是通过this指针实现的。
- 对于构造函数,this指针指向正在创建的对象;
- 对于成员函数,this指针指向该函数的调用对象。
- 显示使用this指针的场景
- 区分作用域;
- 从成员函数返回调用对象自身;
- 从类的内部销毁对象的自身;
- 作为函数的实参,实现对象间的交互。
代码示例
- this.cpp
#include <iostream> using namespace std; class User{ public: /*User(const string& name,int age) :m_name(name),m_age(age){ cout << "构造函数:" << this << endl; }*/ //使用this指针区分成员变量和参数变量 User(const string& m_name,int m_age){ this->m_name = m_name; this->m_age = m_age; } void print(void){ cout << "我叫" << this->m_name << ",今年" << this->m_age << "岁" << endl; }/*编译器编译以后: void print(User* this){ cout << this->m_name << .. << this->m_age << .. }*/ private: string m_name; int m_age; }; int main(void) { User u1("张三",22); cout << "&u1=" << &u1 << endl; User u2("李四",23); cout << "&u2=" << &u2 << endl; u1.print();//User::print(&u1); u2.print();//User::print(&u2); return 0; }
- 执行结果
- 02this.cpp
#include <iostream> using namespace std; class Counter{ public: Counter(int count=0):m_count(count){} Counter& add(void){ ++m_count; //this指向调用对象 //*this就是调用对象自身 return *this;//返回自引用 } void destroy(void){ //... cout << "this=" << this << endl; delete this;//对象自销毁 } int m_count; }; int main(void) { Counter cn; cn.add().add().add(); cout << cn.m_count << endl;//3 Counter* pcn = new Counter; //... cout << "pcn=" << pcn << endl; //delete pcn; pcn->destroy(); return 0; }
- 执行结果
* 03this.cpp
#include <iostream> using namespace std; class Student;//短视声明 class Teacher{ public: //向参数表示的学生对象提问 void educate(Student* s); //获取学生对象回答的答案 void reply(const string& answer); private: string m_answer;//保存答案 }; class Student{ public: //接收问题,并将答案传回给教师对象 void ask( const string& question,Teacher* t); }; void Teacher::educate(Student* s){ s->ask("什么是this指针?",this); cout << "学生回答:" << m_answer << endl; } void Teacher::reply(const string& answer){ m_answer = answer; } void Student::ask( const string& question,Teacher* t){ cout << "问题:" << question << endl; t->reply("this指针指向调用对象的地址"); } int main(void) { Teacher teacher; Student student; teacher.educate(&student); return 0; }
- 执行结果
常成员函数(常函数)
- 在一个成员函数参数表后面加const修饰,表示这个函数是常成员函数。
- 返回类型 函数名(形参表) const{函数体}
- 常函数中的this指针是一个常指针,不能再常函数中修改成员变量的值。(注:被mutable关键字修饰的成员变量,可以在常函数中被修改)
- 非常对象既可以调用常函数也可以调用非常函数,但是常对象只能调用常函数,不能调用非常函数。(注:常对象也包括常指针或常引用)
- 函数名和形参相同的成员函数,其常版本和非常版本可以构成重载关系,常对象调用常数版本,非常对象调用非常版本。
代码示例
- constfunc.cpp
#include <iostream> using namespace std; class A{ public: A(int data = 0):m_data(data){} void print(void) const {//常函数 cout << m_data++ << endl; }/* void print(const A* this){ cout << this->m_data++ << endl; }*/ private: mutable int m_data; }; int main(void) { A a(100); a.print();//100 a.print();//101 a.print();//102 return 0; }
- 执行结果
- 02constfunc.cpp
#include <iostream> using namespace std; class A{ public: //void func1(const A* this) void func1(void) const { cout << "常函数" << endl; } //void func2(A* this) void func2(void){ cout << "非 常函数" << endl; } }; int main(void) { A a; a.func1();//A::func1(&a),A* a.func2(); const A a2 = a; a2.func1();//A::func1(&a2),const A* //a2.func2();//error const A* pa = &a;//pa常指针 pa->func1(); //pa->func2();//error const A& ra = a;//ra常引用 ra.func1(); //ra.func2();//error return 0; }
- 执行结果
- 03constfunc.cpp
#include <iostream> using namespace std; class A{ public: void func(void)const{//const A* this cout << "func常版本" << endl; } void func(void){//A* this cout << "func非常版本" << endl; } }; int main(void) { A a; a.func();//非常版本 const A& ra = a; ra.func();//常版本 return 0; }
- 执行结果
析构函数(Destructor)
- 语法
class 类名{ ~类名(void){ 负责清理对象生命期内动态分配的资源 } }; 1)函数名必须是 “~类名” 2)没有返回类型,也没有参数 3)不能被重载,一个类只能有一个析构函数
- 当对象被销毁时,该对象的析构函数自动被调用和执行;
- 1)栈对象离开作用域时,其析构函数被作用域终止右花括号“}”调用;
- 2)堆对象的析构函数被delete操作符调用。
- 如果一个类没用显示定义析构函数,那么编译器会为这个类提供一个缺省的析构函数;
- 1)对基类类型的成员变量,什么也不做;
- 2)对类 类型成员变量(成员子对象),会自动调用相应类的析构函数。
- 对象的创建和销毁过程
- 1)对象创建
- –》分配内存
- –》构造成员子对象(按声明顺序)
- –》执行构造函数代码
- 2)对象销毁
- –》执行析构函数代码
- –》析构成员子对象(按声明逆序)
- –》释放内存
代码示例
- destructor.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 << "Integer的析构函数" << endl; delete m_data; m_data = NULL; } 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;//delete-->调用析构 cout << "test3" << endl; }//}-->调用析构函数 cout << "test2" << endl; return 0; }
- 执行结果
- 02destructor.cpp
#include <iostream> using namespace std; class A{ public: A(void){ cout << "A::A(void)" << endl; } ~A(void){ cout << "A::~A(void)" << endl; } }; class B{ public: B(void){ cout << "B::B(void)" << endl; } ~B(void){ cout << "B::~B(void)" << endl; } A m_a;//成员子对象 }; int main(void) { B b; return 0; }
- 执行结果
拷贝构造和拷贝赋值
浅拷贝和深拷贝
- 如果一个类中包含指针形式的成员变量,缺省的拷贝构造函数只是复制指针变量本身,而没用复制该指针所指向的内容,这种拷贝方式称为浅拷贝。
- 浅拷贝将导致不同对象之间的数据共享,如果数据在堆区,析构时还可能发送“double free”,导致进程的终止,这时需要定义一个支持复制指针指向内容的拷贝构造函数,即深拷贝。
拷贝赋值
- 当两个对象进行赋值操作时,比如“i3 = i2”,编译器会将其自动翻译成 i3.operator=(i2)成员函数的调用形式,其中“operator=”称为拷贝赋值操作符函数,通过它实现两个对象的赋值操作,该函数的返回结果就是表达式结果。
- 但是编译器缺省提供的拷贝赋值函数和缺省的拷贝构造函数类似,也就是浅拷贝,只是复制了指针变量本身,没用复制指针所指向的内容,有“double free”和内存泄漏的风险。
- 为了得到深拷贝的效果,避免错误,必须自己定义一个支持深拷贝的拷贝赋值函数。
类名& operator=(const 类名& that){ if(&that != this){//防止自赋值 释放旧内存; 分配新内存; 拷贝新数据; } return *this;//返回自引用 } this指向调用对象(左操作数) that对应参数对象(右操作数)
代码示例
- copy.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 << "Integer的析构函数" << endl; delete m_data; m_data = NULL; } /*编译器提供的缺省拷贝构造函数(浅拷贝)*/ /*Integer(const Integer& that){ cout << "缺省的拷贝构造" << endl; m_data = that.m_data; }*/ /*自定义深拷贝构造函数*/ Integer(const Integer& that){ cout << "自定义深拷贝" << endl; //m_data = new int; //*m_data = *that.m_data; m_data = new int(*that.m_data); } private: int* m_data; }; int main(void) { Integer i1(100); Integer i2 = i1;//拷贝构造 i1.print();//100 i2.print();//100 return 0; }
- 执行结果
- 实现string类的基本,string.cpp
#include <iostream> #include <cstring> using namespace std; class String{ public: //构造函数 String(const char* str){ m_str = new char[strlen(str)+1]; strcpy(m_str,str); } //练习:析构函数,拷贝构造 ~String(void){ delete[] m_str; m_str = NULL; } String(const String& that){ m_str = new char[strlen(that.m_str)+1]; strcpy(m_str,that.m_str); } const char* c_str(void)const{ return m_str; } private: char* m_str; }; int main(void) { String s("hello"); cout << s.c_str() << endl;//hello String s2 = s; cout << s2.c_str() << endl;//hello return 0; }
- 执行结果
- 拷贝赋值,copy.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 << "Integer的析构函数" << endl; delete m_data; m_data = NULL; } /*编译器提供的缺省拷贝构造函数(浅拷贝)*/ /*Integer(const Integer& that){ cout << "缺省的拷贝构造" << endl; m_data = that.m_data; }*/ /*自定义深拷贝构造函数*/ Integer(const Integer& that){ cout << "自定义深拷贝" << endl; //m_data = new int; //*m_data = *that.m_data; m_data = new int(*that.m_data); } /*编译器缺省实现的拷贝赋值操作符函数*/ //i3 = i2;//i3.operator=(i2) /* Integer& operator=(const Integer& that){ cout << "缺省拷贝赋值函数" << endl; m_data = that.m_data; return *this; }*/ //自定义深拷贝赋值操作符函数 Integer& operator=(const Integer& that){ cout << "自定义深拷贝赋值" << endl; if(&that != this){ delete m_data; m_data = new int; *m_data = *that.m_data; } return *this; } private: int* m_data; }; int main(void) { Integer i1(100); Integer i2(i1);//拷贝构造 i1.print();//100 i2.print();//100 Integer i3; //i3.operator=(i2); i3 = i2;//拷贝赋值 i3.print();//100 return 0; }
- 执行结果