《C++ —— 笔记》
this指针
在C++中成员变量和成员函数是分开存储的。
每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码。
那么问题是:这一块代码是如何区分那个对象调用自己的呢?
this指针是隐含每一个非静态成员函数内的一种指针
this指针的用途:
* 当形参和成员变量同名时,可用this指针来区分
* 在类的非静态成员函数中返回对象本身,可使用return *this
eg:
class Person { public: Person(int age) { //1、当形参和成员变量同名时,可用this指针来区分 this->age = age; } Person& PersonAddPerson(Person p) { this->age += p.age; //返回对象本身 return *this; } int age; }; void test01() { Person p1(10); cout << "p1.age = " << p1.age << endl; Person p2(10); p2.PersonAddPerson(p1).PersonAddPerson(p1).PersonAddPerson(p1); cout << "p2.age = " << p2.age << endl; } int main() { test01(); system("pause"); return 0; }
const修饰成员函数
常函数:
* 成员函数后加const后我们称为这个函数为**常函数**
* 常函数内不可以修改成员属性
* 成员属性声明时加关键字mutable后,在常函数中依然可以修改
常对象:
* 声明对象前加const称该对象为常对象
* 常对象只能调用常函数
eg:
class Person { public: Person() { m_A = 0; m_B = 0; } //this指针的本质是一个指针常量,指针的指向不可修改 //如果想让指针指向的值也不可以修改,需要声明常函数 void ShowPerson() const { //const Type* const pointer; //this = NULL; //不能修改指针的指向 Person* const this; //this->mA = 100; //但是this指针指向的对象的数据是可以修改的 //const修饰成员函数,表示指针指向的内存空间的数据不能修改,除了mutable修饰的变量 this->m_B = 100; } void MyFunc() const { //mA = 10000; } public: int m_A; mutable int m_B; //可修改 可变的 }; //const修饰对象 常对象 void test01() { const Person person; //常量对象 cout << person.m_A << endl; //person.mA = 100; //常对象不能修改成员变量的值,但是可以访问 person.m_B = 100; //但是常对象可以修改mutable修饰成员变量 //常对象访问成员函数 person.MyFunc(); //常对象不能调用const的函数 } int main() { test01(); system("pause"); return 0; }
友元
友元:让一个函数或者类 访问另一个类中私有成员
友元的关键字为 ==friend==
友元的三种实现:
* 全局函数做友元
* 类做友元
* 成员函数做友元
全局函数做友元
class Building { //告诉编译器 goodGay全局函数 是 Building类的好朋友,可以访问类中的私有内容 friend void goodGay(Building * building); public: Building() { this->m_SittingRoom = "客厅"; this->m_BedRoom = "卧室"; } public: string m_SittingRoom; //客厅 private: string m_BedRoom; //卧室 }; void goodGay(Building * building) { cout << "好基友正在访问: " << building->m_SittingRoom << endl; cout << "好基友正在访问: " << building->m_BedRoom << endl; } void test01() { Building b; goodGay(&b); } int main(){ test01(); system("pause"); return 0; }
类做友元
class Building; class goodGay { public: goodGay(); void visit(); private: Building *building; }; class Building { //告诉编译器 goodGay类是Building类的好朋友,可以访问到Building类中私有内容 friend class goodGay; public: Building(); public: string m_SittingRoom; //客厅 private: string m_BedRoom;//卧室 }; Building::Building() { this->m_SittingRoom = "客厅"; this->m_BedRoom = "卧室"; } goodGay::goodGay() { building = new Building; } void goodGay::visit() { cout << "好基友正在访问" << building->m_SittingRoom << endl; cout << "好基友正在访问" << building->m_BedRoom << endl; } void test01() { goodGay gg; gg.visit(); } int main(){ test01(); system("pause"); return 0; }
成员函数做友元
class Building; class goodGay { public: goodGay(); void visit(); //只让visit函数作为Building的好朋友,可以发访问Building中私有内容 void visit2(); private: Building *building; }; class Building { //告诉编译器 goodGay类中的visit成员函数 是Building好朋友,可以访问私有内容 friend void goodGay::visit(); public: Building(); public: string m_SittingRoom; //客厅 private: string m_BedRoom;//卧室 }; Building::Building() { this->m_SittingRoom = "客厅"; this->m_BedRoom = "卧室"; } goodGay::goodGay() { building = new Building; } void goodGay::visit() { cout << "好基友正在访问" << building->m_SittingRoom << endl; cout << "好基友正在访问" << building->m_BedRoom << endl; } void goodGay::visit2() { cout << "好基友正在访问" << building->m_SittingRoom << endl; //cout << "好基友正在访问" << building->m_BedRoom << endl; } void test01() { goodGay gg; gg.visit(); } int main(){ test01(); system("pause"); return 0; }
继承同名成员处理方式
class Base { public: Base() { m_A = 100; } void func() { cout << "Base - func()调用" << endl; } void func(int a) { cout << "Base - func(int a)调用" << endl; } public: int m_A; }; class Son : public Base { public: Son() { m_A = 200; } //当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数 //如果想访问父类中被隐藏的同名成员函数,需要加父类的作用域 void func() { cout << "Son - func()调用" << endl; } public: int m_A; }; void test01() { Son s; cout << "Son下的m_A = " << s.m_A << endl; cout << "Base下的m_A = " << s.Base::m_A << endl; s.func(); s.Base::func(); s.Base::func(10); } int main() { test01(); system("pause"); return EXIT_SUCCESS; }
总结:
1. 子类对象可以直接访问到子类中同名成员
2. 子类对象加作用域可以访问到父类同名成员
3. 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数
多继承语法
语法:` class 子类 :继承方式 父类1 , 继承方式 父类2...`
class Base1 { public: Base1() { m_A = 100; } public: int m_A; }; class Base2 { public: Base2() { m_A = 200; //开始是m_B 不会出问题,但是改为mA就会出现不明确 } public: int m_A; }; //语法:class 子类:继承方式 父类1 ,继承方式 父类2 class Son : public Base2, public Base1 { public: Son() { m_C = 300; m_D = 400; } public: int m_C; int m_D; };
菱形继承、虚继承
菱形继承的概念:两个派生类继承同一个基类, 又有某个类同时继承者两个派生类。
这样会产测二义性,因为数据会产生两份数据。
可以使用virtual关键字,利用虚继承来只产生一份数据。
class Animal { public: int m_Age; }; //继承前加virtual关键字后,变为虚继承 //此时公共的父类Animal称为虚基类 class Sheep : virtual public Animal {}; class Tuo : virtual public Animal {}; class SheepTuo : public Sheep, public Tuo {}; void test01() { SheepTuo st; st.Sheep::m_Age = 100; st.Tuo::m_Age = 200; cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl; cout << "st.Tuo::m_Age = " << st.Tuo::m_Age << endl; cout << "st.m_Age = " << st.m_Age << endl; } int main() { test01(); system("pause"); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统