目录
一、成员变量与成员函数分开存储
二、this指针
性质:
作用:
三、空指针访问成员函数
C++中空指针也可以调用成员函数,不过要注意是否用到this指针
如果遇到this指针,加上判断,防止代码出错
四、const修饰成员函数
常函数:
本质:person * const this;
本质:const person *const this;
常对象:
1、在C++中,类内的成员变量和成员函数分开存储
首先,对于一个空对象,占用内存空间为1
class person
{
};
void test01()
{
person p;
cout << sizeof(p) << endl;
}
因为C++编译器给每个空对象分配1个字节空间,防止不同空对象占用同一块内存空间,便于区分
2、只有非静态成员变量才属于类的对象上
在person类中加入一个非静态成员变量
class person
{
int m_a; // 非静态成员变量,属于类的对象上
};
void test02()
{
person p;
cout << sizeof(p) << endl;
}
再加上静态成员变量
再加上非静态成员函数
最后加上静态成员函数
总结:只有非静态成员变量才属于类的对象上
概念:上一节中我们知道成员变量与成员函数分开存储,每一个非静态成员函数只会产生一份函数实例,也就是多个同类型的对象共用一块代码,而如何区分究竟是哪个对象调用自己,用到this指针
①this指针是隐含在每一个非静态成员函数内的一种指针
②this指针不需要定义,可以直接使用
①当形参与成员变量同名时,可用this指针加以区分
举例说明:我们先创建类person和测试函数test01,在类内创建属性m_age,函数person,形参age
class person
{
public:
person(int age)
{
m_age = age;
}
int m_age;
};
void test01()
{
person p(20);
cout << p.m_age << endl;
}
此时可正常输出
但是,如果我们将属性m_age改为age得到这个
class person
{
public:
person(int age)
{
age = age;
}
int age;
};
void test01()
{
person p(20);
cout << p.age << endl;
}
同颜色的即为同一个age,无法正常输出
在此基础上,我们在函数内加上this指针
class person
{
public:
person(int age)
{
this->age = age; // 加上this->
}
int age;
};
可以发现3个age是同源的。此时,this就代表p,this->age == p.age;
②在类的非静态成员函数中返回对象本身,可以用return *this;
class person
{
public:
person(int age)
{
this->age = age;
}
void personAdd(person& p) // 函数本体age加上参数P的age
{
this->age += p.age;
}
int age;
};
void test02()
{
person p1(10);
cout << p1.age << endl;
person p2(10);
cout << p2.age << endl;
}
而如果我们想要多次加和
void test02()
{
p2.personAdd(p1);
cout << p2.age << endl;
p2.personAdd(p1).personAdd(p1).personAdd(p1); // 想要多次加和
cout << p2.age << endl;
}
要先修改函数体返回值
person& personAdd(person& p) // 而且要引用
{
this->age += p.age;
return *this; // 返回对象本身
}
而如果函数体返回值不使用引用&,则无法修改值,
因为这样修改完第一次p2后,返回的是另一个变量,并且后面第2次开始修改的都是另一个变量,再另一个变量
class person
{
public:
void show_name()
{
cout << "Joyce" << endl;
}
void show_age()
{
cout << this->m_age << endl;
}
int m_age;
};
void test01()
{
person* p = NULL;
p->show_age(); // 非法访问
p->show_name();
}
对于这段代码,指针p为NULL,调用show_name函数时可以正常输出,因为她只是简单的打印特定的内容,而调用show_age函数时将报错,因为函数内this->m_age;调用了this指针的m_age,而this指针为NULL,造成非法访问
因此,我们在函数内部加上判断
void show_age()
{
if (this == NULL)
{
return;
}
cout << this->m_age << endl;
}
以此便可以防止代码为NULL时出错
①成员函数后加const称该函数为成员函数
②常函数不可以修改成员属性
③成员属性声明时加关键字mutable,在常函数中仍然能修改
接下来创建person类与函数show_name;
class person
{
public:
void show_name()
{
this->m_a = 100; // 非 常对象,可修改
this = NULL;// this指针的指向不可修改
}
int m_a;
};
因为this指针本质是一个指针常量,所以其指向(地址)不可修改,但其指向的值可以修改
不过,如果在函数后加上const,则地址与值都不可修改
不过,如果在常函数中的属性的声明前加上mutable,则可以修改
class person
{
public:
void show_name() const // 这里有const
{
this->m_a = 100; //可修改
}
mutable int m_a; // 加上const
};
①声明对象前加const称该对象为常对象
②常对象只能调用常函数
class person
{
public:
void show_name() const
{
this->m_a = 100;
}
mutable int m_a;
int m_b;
};
void test02()
{
person p;
p.m_b = 20;
}
此时test02内可以修改m_b;接下来在p前加上const使其变成常对象
void test02()
{
const person p;
p.m_b = 20; // 不可修改
p.m_a = 20; // 可修改
}
则m_b不可修改,而m_a由于前面加了mutable,可以修改
同时,在person类中我们再创建一个普通函数func,尝试在test函数中调用刚才的常函数和普通函数
class person
{
public:
void show_name() const // 常函数
{
this->m_a = 100;
}
void func() // 普通函数
{
;
}
mutable int m_a;
int m_b;
};
void test02()
{
const person p; // 创建常对象
p.show_name(); // 常函数
p.func(); // 普通函数
}
无法调用,因为常对象只能调用常函数(因为普通函数可以修改属性)