一、this指针
作用: 指向成员函数所作用的对象
非静态成员函数中可以直接使用this指针来代表该函数作用的指针
静态函数中不能使用this指针 --因为静态成员函数并不具体作用于某个对象
例题:
每个对象的空间中都存放着一个this指针 (×)
解析: 这句话是不对的。在C++中,this
指针并不是显式地存放在每个对象的空间中。实际上,this
指针是一个隐式的、非静态成员函数的参数。当非静态成员函数被调用时,编译器会自动传递一个指向调用该成员函数的对象的指针作为this
指针。这个this
指针是隐含的,不需要在代码中显式声明。
二、静态成员
1.基本概念
在说明前加了static关键字的成员
class CRectangle
{
private:
int w,h;
static int nTotalArea;
static int nTotalNumber;
public:
CRectangle(int w_, int h_);
static void PrintTotal;
};
普通成员变量每个对象有各自的一份,而静态成员变量一共就一份,为所有对象共享。
(sizeof 运算符不会计算静态成员变量
静态成员不需要通过对象就能访问
静态成员变量本质上是全局变量;设置静态成员这种机制的目的是将和某些类紧密相关的全局变量和函数写到类里面去,看上去像一个整体
2.访问静态变量成员
(1)类名::成员名
(2)对象名.成员名
(3)指针->成员名
(4)引用.成员名
注意:在静态成员函数中,不能访问非静态成员变量,也不能调用非静态成员函数。
静态成员函数没有this
指针,它不能直接访问非静态成员变量。如果静态成员函数需要访问非静态
成员变量,它通常需要接收一个指向对象实例的指针或引用作为参数
问:此种写法有什么缺陷?
CRectangle::CRectangle(int w_, int h_)
{
w = w_;
h = h_;
nTotalNumber ++;
nTotalArea += w*h;
}
CRectangle::~CRectangle()
{
nTotalNumber --;
nTotalArea -= w*h;
}
void CRectangle::PrintTotal()
{
cout << nTotalNumber <<","<< nTotalArea << endl;
}
答:临时的隐藏的CRectangle类对象,临时对象在消亡时会调用析构函数,减少total的值,可是这些临时对象生成时却没有增加total的值。
解决办法:为CRectangle类写一个复制构造函数
CRectangle :: CRectangle(CRectangle &r)
{
w = r.w;
h = r.h;
nTotalNumber ++;
nTotalArea += w*h;
}
三、成员对象和封闭类
1.有成员对象的类称为封闭类
class CTyre{
private:
int radius;
int wirth;
public:
CTyre(int r,int w):radius(r),width(w) { }
};
class CEngine{
};
class CCar {
private:
int price;
CTyre tyre;
CEngine engine;
public:
CCar(int p,int tr,int tw);
};
上例中,如果CCar类不定义构造函数,则下面的语句会编译出错
CCar car;
因为编译器不明白car.tyre该如何初始化,car.engine的初始化没问题
任何生成封闭类对象的语句,都要让编译器明白,对象中的成员对象是如何初始化的。
解决方案:通过封闭类的构造函数的初始化列表。
2.封闭类构造函数和析构函数的执行顺序
(1)封闭对象生成时,先执行所有对象成员的构造函数,然后才执行封闭类的构造函数
(2)对象成员的构造函数调用次序和对象成员在类中的说明次序一致,与它们在成员初始化列表中出现的次序无关。
(3)当封闭类的对象消亡时,先执行封闭类的析构函数,然后再执行成员对象的析构函数,与构造函数调用次序相反。
3.封闭类的复制构造函数
封闭类的对象,如果是用默认复制构造函数初始化的,那么它里面包含的成员对象,也会用复式构造函数初始化。
四、友元(friends)
1.友元函数:一个类的友元函数可以访问该类的私有成员
class CCar
{
private:
int price;
friend int MostExpensiveCar( CCar cars[],int total);
};
可以将一个类的成员函数(包括构造、析构函数)说明为另一个类的友元
class B {
public:
void function();
};
class A {
friend void B::function();
};
2.友元类
如果A是B的友元类,那么A的成员函数可以访问B的私有成员
友元类之间的关系不能传递,不能继承,友元类的关系不是相互的
五、常量成员函数
1.如果不希望某个对象的值被改变,则定义该对象的时候可以在前面加const关键字
class Sample {
private:
int value;
public:
Sample() { }
void SetValue() { }
};
const Sample Obj; //常量对象
Obj.SetValue(); //错误 常量对象只能使用构造函数、析构函数和 有const说明的函数(常量方法)
2.常量成员函数
在类的成员函数说明后面可以加const关键字,则该成员函数成为常量成员函数
常量成员函数内部不能改变属性的值,也不能调用非常量成员函数
class Sample {
private:
int value;
public:
void func() {};
Sample() { }
void SetValue() const {
value = 0; //错误
func(); //错误
}
};
const Sample Obj;
Obj.SetValue(); //可以使用
在定义和声明常量成员函数时都应该使用const关键字
3.常量成员函数的重载
class CTest {
private:
int n;
public:
CTest() {n = 1};
int GetValue() const {return n;}
int GetValue() {return 2*n; }
};
两个函数,名字和参数表都一样,但是一个是const,一个不是,算重载
int main() {
const CTest objTest1;
CTest objTest2;
cout << objTest1.GetValue() <<"," << objTest2.GetValue();
return 0;
}
// 输出1,2
4.mutable成员变量
可以在const成员函数中修改的成员变量
class CTest
{
public:
bool GetData() const
{
m_n1++;
return m_b2;
}
private:
mutable int m_n1;
bool m_b2;
};