1.初始化列表
1.1作用
C++提供给了初始化列表语法,用来初始化属性
1.2语法
构造函数():属性1(值1),属性2(值2),属性3(值3)……{}
1.3示例
我们一般都是这样对函数初始化:
#include<iostream>
using namespace std;
class Person {
public:
Person(int a, int b, int c) {
m_A = a;
m_B = b;
m_C = c;
}
int m_A;
int m_B;
int m_C;
};
void test01() {
Person p(10, 20, 30);
cout << "m_A=" << p.m_A << endl;
cout << "m_B=" << p.m_B << endl;
cout << "m_C=" << p.m_C << endl;
}
int main() {
return 0;
}
学到初始化列表后,我们可以进行如下操作:
#include<iostream>
using namespace std;
class Person {
public:
Person() :m_A(10), m_B(20), m_C(30) {
}
int m_A;
int m_B;
int m_C;
};
void test01() {
Person p;
cout << "m_A=" << p.m_A << endl;
cout << "m_B=" << p.m_B << endl;
cout << "m_C=" << p.m_C << endl;
}
int main() {
test01();
return 0;
}
但是这种就把m_A,m_B,m_C写死了,如何才能动态的调整呢?我们可以进行如下的操作:
#include<iostream>
using namespace std;
class Person {
public:
Person(int a,int b,int c) :m_A(a), m_B(b), m_C(c) {
}
int m_A;
int m_B;
int m_C;
};
void test01() {
Person p(30,20,10);
cout << "m_A=" << p.m_A << endl;
cout << "m_B=" << p.m_B << endl;
cout << "m_C=" << p.m_C << endl;
}
int main() {
test01();
return 0;
}
2.类对象作为类成员
c++类中的成员可以是一个类的对象,我们称为该成员为对象成员
class A{};
class B{
A a;
}
B类中由对象A作为成员,A为对象成员。
注意:当其他类对象作为本类成员,构造时候先构造类对象,再构造自身
#include<iostream>
using namespace std;
class Phone {
public:
Phone(string pName) {//创建类的时候就告诉你手机的品牌
p_name = pName;
cout << "Phone的构造函数调用" << endl;
}
string p_name;
};
class Person {
public:
Person(string name, string pName) :m_name(name),m_phone(pName)//初始化列表赋值,在类创建的时候就告诉你人名和手机名
{
cout << "Person的构造函数调用" << endl;
}
string m_name;
Phone m_phone;
};
void test01() {
Person p("张三", "苹果");
cout << p.m_name << "拿着" << p.m_phone .p_name<< endl;
}
void main() {
test01();
}
可以看到先构造的是Phone类,后构造的是Person类。但是析构函数释放的顺序是和构造函数的顺序相反的。
3.静态成员函数
#include<iostream>
using namespace std;
class Person {
public:
//静态成员函数
static void func()
{
m_A = 100;//静态成员函数可以访问静态成员变量
//m_B = 200;静态成员函数不能访问非静态成员变量
cout << "static void func 调用" << endl;
}
static int m_A;//静态成员变量
int m_B;//非静态成员变量
private://静态成员也是有权限限制的
static void func2() {
cout << "static void func2()调用" << endl;
}
};
void test01() {
//访问静态成员函数有两种方式
//1.通过对象调用
Person p;
p.func();
//2.通过类名调用
Person::func();
//Person::func2();类外不能访问私有的静态成员
}
void main() {
test01();
}
4.C++对象模型和this指针
4.1成员变量和成员函数分开存储
在c++中,成员变量和成员函数分开存储,只有非静态成员变量才属于类的对象上。
#include<iostream>
using namespace std;
class Person {
public:
};
void test01() {
Person p;
cout << "size of p=" <<sizeof(p)<< endl;
}
void main() {
test01();
}
可以看到空对象也是占用一个空间,C++编译器会给每个空对象也分配一个字节空间,是为了区分空对象占内存的位置,每个空对象也应该有一个独一无二的内存地址。
#include<iostream>
using namespace std;
class Person {
public:
int m_A;//非静态成员变量,属于类的对象上
static int m_B;//静态成员变量,不属于类的对象上,不占字节
void func(){}//非静态成员函数,也不属于类的对象上
static void func2(){}//静态成员函数不属于类的对象上
};
void test01() {
Person p;
cout << "size of p=" <<sizeof(p)<< endl;
}
void test02() {
Person p;
cout << "size of p=" << sizeof(p) << endl;
}
void main() {
test02();
}
所以,只有非静态成员变量属于类的对象上,剩下的都不属于,一个空对象的sizeof是1。
4.2this指针的用途
由于每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码,那么问题是:这一块代码是如何区分哪个对象调用的自己呢?
C++通过提供特殊的对象指针,this指针解决上述问题,this指针指向被调用的成员函数所属的对象:
- this指针是隐含每一个非静态成员函数内的一种指针
- this指针不需要定义,直接使用即可
this指针的用途:
- 当形参和成员变量同名时,可以用this指针
- 在类的非静态成员函数中返回对象本身,可以使用return *this
4.2.1this解决名称冲突的案例
输出不是一个年龄。我们可以把成员变量age写为m_age;可以改为如下:
两种方式。
4.2.2返回对象本身用*this
#include<iostream>
using namespace std;
class Person {
public:
Person(int age) {
this->age = age;
}
Person& PersonAddAge(Person& p) {
this->age += p.age;//把别人年龄加到自身
return *this;//this指向的p2的指针,而*this指向的是p2的这个对象本体
}
int age;
};
void test01() {
Person p1(18);
cout << "p1的年龄是:" << p1.age<<endl;
}
void test02() {
Person p1(10);
Person p2(10);
p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);
cout << "p2的年龄是:" << p2.age << endl;
}
void main() {
test02();
}
4.2.3.空指针访问成员函数
C++空指针也是可以调用成员函数的,但是也要注意有没有用到this指针,如果用到this指针,需要加以判断保证代码的健壮性。
#include<iostream>
using namespace std;
class Person {
public:
void showClassName() {
cout << "this is Person class" << endl;
}
void showPersonAge() {
if (this == NULL) {
return;
}
cout << "age=" << this->m_age << endl;
}
int m_age;
};
void test01() {
Person* p=NULL;
p->showClassName();
p->showPersonAge();
}
void main() {
test01();
}
4.3const修饰成员函数
4.3.1常函数
- 成员函数后加const后我们称为这个函数为常函数
- 常函数内不可以修改成员属性
- 成员属性声明时加上关键字mutable后,在常函数中依然可以修改
注:
this指针的本质是指针常量,指针的指向是不可以修改的
Person *const this ;const修饰this指针的指向,因此this指针不可以修改指针的指向。如果要让this指针指向的值也不可以修改就需要:const Person *const this;在成员函数中的定义如下:
class Person {
public:
void showPerson()const {
//this->m_A=100;指针的值也不可以修改
//this = NULL;指针的指向不可以修改
}
int m_A;
};
在成员函数后面加一个const,修饰的时this指向,让指针指向的值也不可以修改
常函数:其实就是在成员函数的屁股后面加一个const,这个const是用来修饰this指针的,来让成员函数的指针指向和值都不可以修改,如果需要修改的话可以在变量的前面加一个mutable,如下所示:
这时候就不会报错,m_B就可以修改。
4.3.2常对象
- 声明对象前加const称该对象为常对象
- 常对象只能调用常函数
在对象前加一个const就是常对象。
常对象也只能调用常函数:
5.友元
例如家里有客厅(public)、卧室(private),客厅所有的客人都可以访问,但是我们的卧室是私有的,也就是只有你可以进去,你也可以允许你的闺蜜进去。
在程序里有些私有属性,也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术。
友元的目的就是让一个函数或者类访问另一个类中私有成员。友元的关键词是friend
友元的三种实现:
- 全局函数做友元
#include<iostream>
using namespace std;
class Building {
public:
Building() {
m_SittingROOM = "客厅";
m_BedRoom = "卧室";
}
public:
string m_SittingROOM;//客厅
private:
string m_BedRoom;//卧室
};
//全局函数
void goodGay(Building *building) {
cout << "好朋友的全局函数正在访问:" << building->m_SittingROOM << endl;
}
void test01() {
Building building;
goodGay(&building);
}
void main() {
test01();
}
可以看到全局函数不能访问私有变量。如果要访问可以加一个friend作为友元
可以看到不再报错。
- 类做友元
#include<iostream>
using namespace std;
class Building {
//Goodgay类是本类的好朋友,可以访问本类中私有成员
friend class GoodGay;
public:
Building();//一般我们都是类内实现成员函数,现在我们尝试一下类外
public:
string m_SittingRoom;//客厅
private:
string m_BedRoom;//卧室
};
class GoodGay {
public:
GoodGay();
void visit();//参观函数访问Building中的属性
Building* buildding;
};
Building::Building() {//类外写成员函数
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
GoodGay::GoodGay() {
//创建一个建筑物的对象
buildding = new Building;
}
void GoodGay::visit() {
cout << "好朋友类正在访问:" << buildding->m_SittingRoom << endl;
cout << "好朋友类正在访问:" << buildding->m_BedRoom << endl;
}
void test01() {
GoodGay gg;
gg.visit();
}
void main() {
test01();
}
- 成员函数做友元
#include<iostream>
using namespace std;
class Building {
//告诉编辑器,Goodgay类下的visit()是本类的好朋友,可以访问本类中私有成员
friend void GoodGay::visit();
public:
Building();//一般我们都是类内实现成员函数,现在我们尝试一下类外
public:
string m_SittingRoom;//客厅
private:
string m_BedRoom;//卧室
};
class GoodGay {
public:
GoodGay();
void visit();//让visit函数可以访问Building中私有成员
void visit2();//让visit2不可以访问Building中私有成员
Building* buildding;
};
Building::Building() {//类外写成员函数
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
GoodGay::GoodGay() {
//创建一个建筑物的对象
buildding = new Building;
}
void GoodGay::visit() {
cout << "好朋友类正在访问:" << buildding->m_SittingRoom << endl;
cout << "好朋友类正在访问:" << buildding->m_BedRoom << endl;
}
void GoodGay::visit2() {
cout << "好朋友类正在访问:" << buildding->m_SittingRoom << endl;
//cout << "好朋友类正在访问:" << buildding->m_BedRoom << endl;
}
void test01() {
GoodGay gg;
gg.visit();
gg.visit2();
}
void main() {
test01();
}
visit()可以访问私有属性,visit2不可以访问。