一.this指针
I.定义
一个隐含于每一个成员函数中的特殊指针,它是一个指向操作该成员函数的对象
II.使用场景
当一个对象调用成员函数时,编译程序先将对象的地址赋值给this指针,然后再调用成员函数存取数据成员时,由隐含作用this指针
III.产生起源
在C++产生初期,没有专门的C++编译器,处理方法就是将C++代码翻译成c的代码,然后通过C编译器进行编译
//C++程序
using namespace std;
class Studnet {
public:
int age;
void Setage(int p);
};
void Studnet::Setage(int p){
age=p;
}
int main(){
Student td;
td.Setage(34);
return 0;
}
//翻译为c程序后如下
struct Student {
int age;
};
void Setage(struct Student *this,int p){
this->age=p;
}
int main(){
struct Student td;
Setage(&td,34);
return 0;
}
IV.作用
指向成员函数所作用的对象
具体使用:
场景一:
非静态成员函数可以直接通过this来代表指向该函数作用的对象的指针
using namespace std;
class Complex {
public:
double imag,real;
public:
void Print(){cout<<real<<","<<imag;}
Complex(double r,double i){imag=i,real=r}
Complex Addone(){
this->real++;
this->Print();
}
};
int main(){
Complex c1(1,3),c2(7,8);
c2= c1.Addone();
return 0;
}
场景二:
using namespace std;
class Student{
public:
int age;
public:
void Hello(){cout <<"hello"<<endl;}
//等价于void Hello(Student *this){cout<<"hello"<<endl;}
};
int main(){
Student *p=NULL;//空指针
p->Hello();//类似于Hello(p);
return 0;
}
注意:
静态成员函数中不能使用this指针,因为静态成员函数并不具体作用与某个对象
典型例题
问题解析:
错误答案为C,在对象生成的过程中,内存会给新对象的成员变量分配内存空间,对于成员函数则不会分配内存空间,其函数代码段存储在另一空间中,仅有一份,如果对象需要使用成用函数,将通过this(也只有一份)指向该对象,完成操作
具体存储方式详见:https://blog.csdn.net/fuzhongmin05/article/details/59112081/
二.静态成员变量(函数)
定义
static关键字修饰的成员变量和成员函数
特点
普通的成员变量每个对象各有一份,静态成员变量一共就一份,为所有对象所共享。
普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用于某个对象
静态成员不需要通过对象就能访问
注意:
(1)sizeof运算符不会计算静态成员变量
(2)必须在定义类的文件中对静态成员变量进行一次说明或初始化
(3)在静态成员函数中,不能访问非静态成员变量(函数)(对象不明)
本质
静态成员变量(函数)本质上是全局变量(函数),对象存在与否,类的静态成员变量都存在
目的:
将和某些类紧密相关的全局变量和函数写到类中,看上去像一个整体,易于维护和理解
访问方式
方式一:
格式:类名::成员名
using namespace std;
class Studnet {
public:
static int age;//静态成员变量
static Print(){cout<<"Hello World!"<<endl;}//静态成员函数
};
int main(){
Student::Print();//方式1
return 0;
}
方式二:
格式:对象名.成员名
using namespace std;
class Studnet {
public:
static int age;//静态成员变量
static Print(){cout<<"Hello World!"<<endl;}//静态成员函数
};
int main(){
Student td;
td.Print();//方式二
return 0;
}
方式三:
格式:指针->成员名
using namespace std;
class Studnet {
public:
static int age;//静态成员变量
static Print(){cout<<"Hello World!"<<endl;}//静态成员函数
};
int main(){
Student *td=&r;//并不具体某一对象
td->Print();//方式三
return 0;
}
方式四:
格式:引用.成员名
using namespace std;
class Studnet {
public:
static int age;//静态成员变量
static Print(){cout<<"Hello World!"<<endl;}//静态成员函数
};
int main(){
Student &td=r;
td.Print();//方式四
return 0;
}
对象在生成时的初始化可能会使用构造函数或复制构造函数
三.成员对象和封闭类
定义
有成员对象(类的成员为其他类的对象)的类成为封闭类
任何生成封闭类对象的语句,都要让编译器明白,对象中的成员对象,是如何初始化的。
具体做法是:
通过封闭类的构造函数的初始化列表(可以为表达式,包含变量、函数)初始化
封闭类构造函数和析构函数的执行顺序
(1)封闭类对象生成时,先执行所有对象成员的构造函数,然后再执行封闭类的构造函数
(2)对象成员的构造函数调用次序和对象成员在类中的说明次序一致,与它们在成员函数初始化列表中出现的次序无关
(3)封闭类对象消亡时,先执行封闭类的析构函数,然后再执行成员对象的析构函数。
实际例子如下:
using namespace std;
class CTyre{
public:
//构造函数
CTyre(){cout<<"CTyre constructor"<<endl;}
//析构函数
~CTyre(){cout<<"CTyre destructor"<<endl;}
};
class CEngine{
public:
//构造函数
CEngine(){cout<<"CEngine constructor"<<endl;}
//析构函数
~CEngine(){cout<<"CEngine destructor"<<endl;}
};
class CCar{
private:
CEngine engine;
CTyre tyre;//成员对象
public:
//构造函数
CCar(){cout<<"CCar constructor"<<endl;}
//析构函数
~CCar(){cout<<"CCar destructor"<<endl;}
};
int main(){
CCar car;
return 0;}
运行结果:
四.友元(friends)
分类:友元函数和友元类
I.友元函数
定义:
一个类的友元函数可以访问该类的私有成员
实例:
using namespace std;
calss CCar;//类声明
class CDriver{
public:
void ModifyCar(CCar *pCar);
};
class CCar{
private:
int price;
friend int MostExpensiveCar(CCar cars[],int total);//声明友元
friend void CDriver::ModifyCar(CCar *pCar);//声明友元
};
void CDriver::ModifyCar(CCar *pCar)
{
//访问私有成员
pCar->price+=1000;//汽车改转后价值增加
}
//求最贵汽车的价格
int MostExpensiveCar(CCar cars[],int total){
int tepMax=-1;
for(int i=0;i<total;++i)
if(cars[i].price>tmpMax)//访问私有成员
tmpMax=cars[i].price;
return tmpMax;
}
int main(){
return 0;}
II.友元类
定义
如果A是B的友元类,那么A的成员函数可以访问B的私有成员
注意:友元类之间的关系不能传递,不能继承,若类A是类B的友元,反之不可,即友元关系不是相互的
实例
using namespace std;
class CCar{
private:
int price;
friend calss CDriver;//声明CDriver为友元类
};
class CDriver{
public:
CCar myCar;
void ModifyCar()//改装汽车
{
myCar.price+=1000;//因CDriver是CCar的友元类,故此处可以访问私有成员
}
};
iny main(){
return 0;
}