类和对象详谈
来源:互联网 发布:查错别字的软件 编辑:程序博客网 时间:2024/06/06 05:46
this指针:对一个实例来说,可以看到它的成员函数和成员变量,但实例本身不可见,this指针时时刻刻指向这个实例。
class student{public:void Initstudent(char* name,int age,char* gender){strcpy(_name,name);_age = age;strcpy(_gender,gender);}private:char _name[20];int _age;char _gender[3];};
void FunTest()
{
cout<<sizeof(student)<<endl;
}说明:
(1)this指针的类型:类类型 * const,以此为例,student * const;
(2)this指针不影响sizeof的结果,不是对象本身的一部分;
(3)this指针是类成员函数的第一个默认隐含参数,由系统编译器自动维护传递,不可显式传递;
(4)this指针的作用域在类的非静态成员函数内部;
关于类的成员函数的 _thiscall调用约定:
(1)_thiscall仅能够用于类的成员函数上,且参数从右向左压栈;
(2)若类的成员函数参数个数确定,this指针通过ecx传递给被调用者;
(3)若类的成员函数参数个数不确定,则this指针在所有参数被压栈后压入堆栈且调用者清理堆栈,否则函数自己清理堆栈;
那么,为什么叫this指针,而不是引用呢?
this指针的类型为 类类型 * const,它是一个常指针,它的指向保证不会改变;而引用的实质也是利用指针来进行操作。
this指针能否为NULL呢?
class A{public: void FunTest1() {}};void FunTest(){ A* pt=NULL; pt->FunTest1();}经过验证,this指针可以为NULL;但原因还是有点迷茫。
类的默认成员函数
构造函数:特殊的成员函数,函数名与类名相同,创建类类型对象时,由编译器自动调用,在对象的生命周期内有且仅调用一次,以保证每一个数据成员有一个合适的初始值;
特征:
(1)构造函数没有返回值类型,注意:没有返回值类型与返回值类型为void是两回事;
(2)一个类可以有多个构造函数(包括一个拷贝构造函数,其余称为普通构造函数);
(3)构造函数有初始化列表(可以不使用);
(4)创建类类型对象时,由编译器自动调用,在对象的生命周期内有且仅调用一次;若没有显式定义构造函数,编译器会提供一个默认的构造函数;
(5)构造函数可以重载,实参决定了调用哪个构造函数;
class A{public:A(){cout<<"A()"<<endl;}A(const int year,const int month,const int date){ _year = year;_month = month;_date = date;cout<<_year<<"-"<<_month<<"-"<<_date<<endl;}private:int _year;int _month;int _date;};
(6)无参构造函数和带有缺省值的构造函数都认为是缺省构造函数,且缺省构造函数只能有一个;
class A{public:/*A(){}*/A(const int year=1,const int month=2,const int date=3){_year = year;_month = month;_date = date;}private:int _year;int _month;int _date;};构造函数的初始化列表:位于函数参数表之后,却在函数体{}之前,说明该表里的初始化工作发生在函数体内的任何代码被执行之前;
形如:
初始化顺序:
(1)每个成员在初始化列表中只能出现一次(因为数据成员的初始化仅有一次);
(2)数据成员在类中的定义顺序就是在初始化列表中的初始化顺序,注意:初始化列表仅能初始化数据成员;
class A{public:A(){cout<<"A()"<<endl;}A(const int year,const int month,const int date):_year(year),_month(month),_date(date){cout<<_year<<"-"<<_month<<"-"<<_date<<endl;}private:int _year;int _month;int _date;};
(3)避免使用数据成员初始化数据成员,以免引来不必要的麻烦;
类中哪些成员必须要放在初始化列表中初始化?
class Time{public: Time(const int hour,const int minute,const int second ) :_hour(hour) ,_minute(minute) ,_second(second) {}private: int _hour; int _minute; int _second;};class Date{public: Date() :a(0) ,t(2017,2,28) {}private: const int a; Time t;};类中的引用数据成员、const数据成员、类类型成员(该类没有缺省的构造函数)都必须在初始化列表中初始化;
默认构造函数:若类没有显式定义构造函数时,编译器会自动合成一个构造函数,该构造函数中什么都不做;
那么,什么时候编译器会自动合成构造函数呢?
构造函数的作用:创建对象、初始化对象和类型转换(用explicit修饰构造函数,抑制由构造函数定义的隐式转换);
拷贝构造函数:特殊的构造函数,只有单个形参,且参数是本类类型对象的引用(常用const修饰),创建对象时使用已存在的同类对象来进行初始化,由编译器自动调用。
Date(const Date& d){ _year = d._year; _month = d._month; _date = d._date;}特点:(1)是构造函数的重载;(2)参数必须使用同类型对象的引用传递;
(3)若没有显式定义,系统会自动合成默认的拷贝构造函数,同时,会依次拷贝类的数据成员完成初始化;
拷贝构造函数的使用场景:
(1)对象实例化对象
Date d1(2017,2,28);Date d2(d1);(2)将拷贝构造函数的返回值作为函数的参数
void FunTest(const Date d){}(3)传值方式作为函数的返回值
Date FunTest(){Date d;return d;}析构函数:析构函数名与类名相同,函数名前加“~”,功能与构造函数功能相反,在对象被销毁时,由编译器自动调用,完成类的一些资源清理工作;
特点:(1)析构函数没有返回值类型,也没有参数;
(2)一个类中必须有且只能有一个析构函数,若没有显式定义析构函数,编译器会自动合成缺省的析构函数;
(3)析构函数的本质是做一些清理工作,并不是删除对象,且在对象生命周期结束时,编译器会自动调用析构函数;
class Carray{public:Carray(int cap) //构造函数:_cap(cap){_pt = (int*)malloc(cap*sizeof(int));_size = 0;}~Carray() //析构函数{ if(NULL != _pt){free(_pt);_pt = NULL;}_size = 0;_cap = 0;}private:int *_pt;int _size;int _cap;};拷贝构造函数和赋值运算符重载的重要性
(1)若不主动编译拷贝构造函数和赋值运算符重载函数,编译器将以“位拷贝”的方式自动生成缺省的函数;若类中含有指针变量,则这两个缺省的函数就隐含了错误;
以类String的两个对象a,b为例,假设a.m_data的内容为“hello”,b.m_data的内容为“world”;现将a赋给b,缺省的赋值运算符重载函数的“位拷贝”意味着执行b.m_data=a.m_data,但这将造成三个错误:【1】b.m_data原有的内存没被释放,造成内存泄露;【2】b.m_data和a.m_data指向同一块内存空间,a或b任何一方变动都会影响另一方;【3】在对象被析构时,m_data被释放了两次;
(2)拷贝构造函数与赋值运算符重载函数的区别:拷贝构造函数是在对象被创建时调用的,而赋值运算符重载函数只能被已经存在的对象调用;
类的静态成员:声明为static的类成员;
特点:(1)类的静态成员被所有类对象所共享,不属于某一个具体的实例;
(2)类的静态成员在类中声明,在类外定义(不添加static关键字);
(3)类静态成员的访问形式:类名::静态成员或对象.静态成员;
(4)类静态成员有public、protected和private三种访问权限,具有返回值、const修饰符等参数;
(5)类静态成员函数没有默认的this指针,非静态成员函数中有默认的this指针(this指针的作用域在非静态成员函数的内部);
说明:类的静态成员函数中没有默认的this指针,所以它无法调用类的静态或非静态成员函数;
类的非静态成员函数可以调用类的静态或非静态成员函数,因为不需要this指针;
const关键字
在c中,const int a=10;a是不被修改的变量,称为常变量,可通过数组验证;
在c++中,const int a=10;int arr[a]可通过,表明a为常量;
const int a=10; //a为常量int* pa = (int*)&a;*pa = 100;cout<<a<<endl; //用10将a替换,打印10cout<<*pa<<endl;//打印100
const修饰类成员
使用场景:(1)const修饰形参,一般和引用同时使用且修饰返回值,同时,在构造函数的初始化列表中修饰类数据成员;
(2)const修饰类的成员函数,实际修饰隐含的this指针,表明在类中不可以对类中的成员进行修改;
(3)在const修饰的类的成员函数中,若要对类的数据成员进行修改,则在该数据成员定义声明前加mutable关键字;
说明:【1】非静态成员函数中有默认的this指针,可用const修饰;静态成员函数和普通函数中没有默认的this指针,所以不可用const修饰;
【2】const对象可调用const成员函数(实质是const修饰的是this指针,则this指针的类型为const Date* const);
【3】非const对象可以调用const成员函数(this指针的类型为const Date* const )和非const成员函数(this指针的类型为Date* const);
【4】const成员函数(this指针的类型为const Date* const)内可以调用其它的const成员函数(this指针的类型为const Date* const);
【5】非const成员函数(this指针的类型为Date* const)可调用其它的const成员函数(this指针的类型为const Date* const)和非const成员函数(this指针的类型为Date* const);
class A{public:void FunTest1()const{}void FunTest2(){}void FunTest3()const{FunTest1();}void FunTest4(){FunTest1();FunTest2();}};void FunTest(){const A a1;a1.FunTest1();A a2;a2.FunTest3();a2.FunTest4();}
- 类和对象详谈
- 详谈java类和对象的生命周期
- 详谈接口和抽象类
- Java面向对象详谈——类与对象
- String类和StringBuffer类的详谈
- 详谈 IEnumerator 和 IEnumberator
- 详谈Javascript中的String对象
- 详谈Java I/O中类的用途和区别
- Java面向对象详谈——封装、继承和多态
- JVM类加载,详谈
- 详谈String类
- 详谈String类
- android -详谈Style和Theme
- 详谈Javascript中的Array数组对象
- 详谈ASP.NET的DataReader对象
- 【常见面试题目C++系列】C++中空类和空结构体大小(sizeof)详谈
- 详谈TC和BC的几个Path
- [转]缓存技术详谈和代码实现
- android developer tiny share-20170221
- Linux内核中的spin_lock理解
- 内存管理之函数mm_init解读之mem_init
- vlan间的路由(三)
- X86架构对KVM支持
- 类和对象详谈
- 跨时钟域处理
- 常用Atom插件列表
- Java-Basic-Arrays
- Struts2异常处理
- 你不能错过的2016Java技术调查
- vaadin之UI组件
- Java面向对象(一)
- GCD介绍: 基本概念和Dispatch Queue