笔记分享|C++学习笔记(B站黑马程序员C++教程)

C++学习笔记(B站黑马程序员C++教程) 简介

视频链接https://www.bilibili.com/video/BV1kV411U7Ub?spm_id_from=333.999.0.0
建议用python或者浏览器视频插件把视频先下下来,万一没了呢!!!
第10-20章
目录
十一、动态对象创造
十二、静态成员函数
十三、 单例模式
十四、 初识对象和this指针
十五、 空指针访问成员函数
十六、 全局函数做友元函数
十七、动态数组
十八、运算符重载
十九、强化训练字符封装
二十、继承
十一、动态对象创造
动态对象创造 //malloc 和 new 的区别 //malloc 和 free属于库函数new 和delete属于运算符 //malloc不会调用构造函数new 会调用构造函数 // malloc返回void * C++下需要强转new返回创建的对象指针 class Person { public: Person() { cout << "Person构造函数构造调用" << endl; } Person(int a) { cout << "Person有参构造函数构造调用" << endl; } ~Person() { cout << "Person析构函数构造调用" << endl; }private:}; void test01() { Person* p = new Person; delete p; } //注意事项: //不要用void *去接受new出来的对象 // void test02() { void* p = new Person; delete p; //用不了析构无法释放 delete (Person*)p; //这么可以但不提倡 }//利用new开辟数组 void test03() { //常规数组 //int* pint = new int[10]; //double* pD = new double[10]; //会调用默认构造函数,堆区调用数组一定会调用默认构造函数 //尽量用new新建class后,建立默认函数,否则有可能在类建立带参构造函数时,系统不自带初始默认函数 Person* p_Person = new Person[10]; delete[] p_Person; //释放数组多加一个[] }void test04() { //栈上开辟数组,可以没有默认构造 Person pArray[10] = { Person(10),Person(20) ,Person(30) }; }

十二、静态成员函数
静态成员变量 //1.静态成员变量 class MyClass { public: MyClass() { } ~MyClass() { } //静态成员变量,编译阶段分配了内存 //必须类内声明、类外初始化 //静态成员变量 所有对象都共享同一份数据 static int m_a; private: static int m_b; }; int MyClass::m_a = 0; void test() { //1.通过对象进行访问 MyClass p1; cout << p1.m_a << endl; MyClass p2; p2.m_a = 100; cout << p2.m_a << endl; //2.通过类名进行访问 cout << MyClass::m_a << endl; //cout << MyClass::m_b << endl; //私有静态变量类外访问不到,静态变量有访问权限 } 静态成员函数 //静态成员函数 //所有对象都共享一个成员函数 //注意:静态函数只能调用静态变量 class Person { public: //静态成员函数 //所有对象都共享一个成员函数 //注意:静态函数只能调用静态变量 static void func() { m_b = 20; /*m_a = 10; */ cout << "func调用" << endl; }private: int m_a = 0; static int m_b; }; int Person::m_b = 100; void test01() { //1.通过对象 Person p1; p1.func(); //2.通过类名 Person::func(); }

十三、单例模式
主席案例 //单利全局只有一个 //单例模式主席类案例 class ChairMan { public: static ChairMan* GetInstance()//实例 { return SingleMan; }private: //将构造函数私有化,不可以创建多个对象 ChairMan() {}; ChairMan(const ChairMan&) {}; //public:将主席指针私有,对外只提供制度接口,防止主席被释放 static ChairMan* SingleMan; //类内声明,类外初始化}; ChairMan* ChairMan::SingleMan = new ChairMan; void test01() { /*ChairMan* c1 = ChairMan::SingleMan; */ /*ChairMan::SingleMan = NULL; *///不能直接操作值 ChairMan* c1 = ChairMan::GetInstance(); /*ChairMan* c3 = new ChairMan(c1); */ delete c1; //可以释放操作} 打印机案例 //单利打印机 class Printer { public: static Printer* GetInstance() { return printer; } void PrinterTest(string test) { m_count++; cout << test << endl; } int m_count; private: Printer() { m_count = 0; }; Printer(const Printer &p) {}; static Printer* printer; //编译阶段分配内存,程序没运行打印}; Printer* Printer::printer = new Printer; void test02() { Printer* p1 = Printer::GetInstance(); p1->PrinterTest("入职证明"); p1->PrinterTest("身份证"); Printer* p2 = Printer::GetInstance(); p2->PrinterTest("打印机使用次数"); cout << p2->m_count << endl; /*cout << Printer::m_count << endl; *///非静态成员只能对应某个对象访问}

十四、初识对象和this指针
class Person{}; sizeof(Person)==1//空对象内存为一字节class Person { int a; int func(); }; sizeof(Person)==4//原因成员函数存储空间分开存储#pragma pack(show)对齐模数只有非静态成员变量属于对象上,其他都是一份;this指针 class Person { int a; int func(this); //隐式添加,谁调用this就指向谁 }; //this指针 //用途1:解决名称冲突 //性质:隐藏在每个成员函数中 //*this 本体 //链式编程思想class Person { public: Person(int age)//Person * this类型 { m_age = age; this->age = age; //成员变量重名用this 区分 } Person& PersonAddPerson(Person& p) { this->age += p.age; return *this; } int age; int m_age; private:}; void test01() { Person p1(18); cout << p1.age << endl; Person p2(10); p1.PersonAddPerson(p2).PersonAddPerson(p2).PersonAddPerson(p2); //链式编程 cout <<"p1.age为" << p1.age << endl; }

十五、空指针访问成员函数
空指针 1.成员函数没有用到this指针可以调用 2.成员函数有用到this指针不可以调用 class Person { public: Person(){}; ~Person(){}; void ShowClass() {cout << "class Name is Person" << endl; } void ShowAge() { if (this == NULL) {//防止调用空指针,防止代码崩掉 return; } m_age = 0; cout << "age = " << this->m_age << endl; } int m_age; private:}; void test01() { Person* p = NULL; //没有类空间成员属性可以调用 p->ShowClass(); //有类空间成员属性不可以调用 p->ShowAge(); } 常函数和常对象 常对象只可以修改加mutable前缀属性,和常数调用,不可以调普通成员函数和普通属性 目的给*this 指针加上const使指针的值也不可以改变 class Person { public: Person(){}; Person(int age) { this->m_age = age; }; /*void ShowPerson() {*/ void ShowPerson() const{ //在一个类函数后边加const 修饰成员函数中的this指针 //Person * const this变成const Person * const this/*m_age = 100; *///常函数下不对 m_a = 100; //特殊的属性也可以改//防止m_age修改 //this指针的本质 Person * const this //const Person * const this 所有都不能修改cout << "Person age = " << m_age << endl; } ~Person(){}; int m_age; mutable int m_a; //在常函数中常对象加 mutable 特殊的属性也可以改 }; void test01() { Person p(10); //常对象只可以修改加mutable前缀属性,和常数调用,不可以调普通成员函数和普通属性 const Person p1(10); p1.ShowPerson(); p1.m_a = 10; }

十六、全局函数做友元函数
注意:friend不具有互逆行,只有定义friend才可以访问 //友元函数,可以把一个全局函数,某个类中的成员函数,甚至整个类声明为友元 class Buliding { friend void goodfriend(Buliding* buliding); public: Buliding(){ this->m_sittingrom = "客厅"; this->m_bedroom = "卧室"; }; ~Buliding(){}; string m_sittingrom; private: string m_bedroom; }; //好朋友全局函数,可以访问Buliding的私有属性 void goodfriend(Buliding* buliding) { cout << "好朋友正在访问:" << buliding->m_sittingrom << endl; cout << "好朋友正在访问:" << buliding->m_bedroom << endl; } void test01() { Buliding buliding; goodfriend(&buliding); } 整个类作为友元 class Building; //类的声明class GoodFriend { public: GoodFriend(); void visit(); Building* m_building; ~GoodFriend(){}; private:}; class Building { //让goodfriend友元 friend class GoodFriend; public: Building(); string m_sittingrom; ~Building(){}; private: string m_bedrom; }; Building::Building() { this->m_sittingrom = "客厅"; this->m_bedrom = "卧室"; }GoodFriend::GoodFriend() { this->m_building = new Building; }void GoodFriend::visit(){ cout << "好朋友正在访问" << this->m_building->m_sittingrom << endl; cout << "好朋友正在访问" << this->m_building->m_bedrom << endl; }void test01() { GoodFriend ff; ff.visit(); } friend void GoodFriend::visit(); 某个类成员函数作为友元;

十七、动态数组
MyArry.h #pragma once #define _CRT_SECURE_NO_WARNINGS #include using namespace std; class MyArray { public: MyArray(); //默认构造给100个容量 MyArray(int capacity); MyArray(const MyArray &arr); //尾插法 void PushBack(int val); //根据位置设置数据 void SetData(int pos, int val); //根据位置获取数据 int GetData(int pos); //中括号获取数组元素 int* GetArray(); //获取数组大小 int GetSize(); ~MyArray(); private: int m_capacity; //数组容量 int m_size; //数组大小 int* pAddress; //真实在堆区开辟的数组的指针}; MyArry.cpp #include"MyArray.h"//默认构造给100个容量 MyArray::MyArray() { this->m_capacity = 100; this->m_size = 0; this->pAddress = new int[this->m_capacity]; }MyArray::MyArray(int capacity) { this->m_capacity = capacity; this->m_size = 0; this->pAddress = new int[this->m_capacity]; }MyArray::MyArray(const MyArray& arr) { this->m_capacity = arr.m_capacity; this->m_size = arr.m_size; this->pAddress = new int[arr.m_capacity]; for (int i = 0; i < m_size; i++) { this->pAddress[i] = arr.pAddress[i]; } }//尾插法 void MyArray::PushBack(int val) { this->pAddress[this->m_size] = val; this->m_size++; }//根据位置设置数据 void MyArray::SetData(int pos, int val) { this->pAddress[pos] = val; }//根据位置获取数据 int MyArray::GetData(int pos) { return this->pAddress[pos]; }//中括号获取数组元素 int* MyArray::GetArray() { return this->pAddress; }//获取数组大小 int MyArray::GetSize() { return this->m_size; }MyArray::~MyArray() { if (this->pAddress != NULL) { delete[] this->pAddress; this->pAddress = NULL; } } test.cpp #define _CRT_SECURE_NO_WARNINGS #include #include"MyArray.h"using namespace std; //测试功能 void test01() { MyArray arr; for (int i = 0; i < 10; i++) { arr.PushBack(i); } for (int i = 0; i < arr.GetSize(); i++) { cout << arr.GetData(i) << endl; } MyArray arr2(arr); for (int i = 0; i < arr2.GetSize(); i++) { cout << arr2.GetData(i) << endl; } arr.SetData(0, 1000); cout << "arr[0] = " << arr.GetData(0) << endl; int *arr3 = arr.GetArray(); arr3[0] = 10; cout << "arr3[0] = " << arr.GetData(0) << endl; cout << "arr3[0] = " << arr3[0] << endl; }int main(int argc, char* argv[]) { test01(); system("pause"); return EXIT_SUCCESS; }

十八、运算符重载
加号运算符重载 注意:加号重载运算符可以重载函数 //Person p3 = operator+(p1,p2); //全局函数本质//Person p3 = p1.operator+(p2); //全局函数本质 class Person { public: Person(){}; //注意大括号; Person(int a,int b):m_a(a),m_b(b) { }; 利用函数实现加号运算符重载 //Person operator+(Person& p) //{ // Person temp; // temp.m_a = this->m_a + p.m_a; // temp.m_b = this->m_b + p.m_b; // return temp; //} ~Person(){}; int m_a; int m_b; }; //利用全局函数加号运算符重载 Person operator+(Person& p1, Person& p2) { Person temp; temp.m_a = p1.m_a + p2.m_a; temp.m_b = p1.m_b + p2.m_b; return temp; }void test01() { Person p1(10, 10); Person p2(20, 20); Person p3 = p1 + p2; //Person p3 = operator+(p1,p2); //全局函数本质 //Person p3 = p1.operator+(p2); //全局函数本质 //不影响 int a = 0, b = 3; int c = a + b; cout << "c = " << c << endl; cout << "p3.m_a = " << p3.m_a << "p3.m_b = " << p3.m_b << endl; } 左移运算符<< 全局本质是用 operator<<(ostream& cout, Person& p)替代 cout << "m_a =" << p.m_a << "m_b = " << p.m_b; 即 运算符前后数据替代 类本质是本类在前,其他在后的本质,如p1.operator(ostream& cout); 这处之所以不能用,cout在后边了 class Person { friend ostream& operator<<(ostream& cout, Person& p); public: Person(int a, int b) { this->m_a = a; this->m_b = b; }; //void operator<<(Person& p) //p.operator<<(cout)p<m_age = age; } void ShowAge() { cout << "年龄为: " << this->m_age << endl; } ~Person() { cout << "Person的析构调用" << endl; }private: int m_age; }; class SmartPoint { public: SmartPoint(Person *person) { this->m_person = person; } ~SmartPoint() { if (this->m_person) { delete this->m_person; this->m_person = NULL; } } //重载->运算符 Person* operator->() { return this->m_person; } //重载* 运算符 Person& operator*() { return *m_person; } //Person operator*()//直接返回值针是拷贝构造 //{ // return *m_person; //}private: Person* m_person; }; void test01() { //Person* p = new Person(18); //(*p).ShowAge(); //p->ShowAge(); //delete p; //利用智能指针 管理new出来的person的释放操作 SmartPoint sp(new Person(18)); sp->ShowAge(); //本质sp->->ShowAge(); (*sp).ShowAge(); } 赋值运算符重载 class Person { public: Person() {}; Person(const char *name,int age) { this->m_name = new char[strlen(name) + 1]; strcpy(this->m_name, name); this->m_age = age; } Person(const Person &p) { this->m_name = new char[strlen(p.m_name) + 1]; strcpy(this->m_name, p.m_name); this->m_age = p.m_age; } //重载 = Person& operator=(const Person& p) { //先判断原来堆区是否有内容,有先释放 if (this->m_name != NULL) { delete[] this->m_name; this->m_name = NULL; }this->m_name = new char[strlen(p.m_name) + 1]; strcpy(this->m_name, p.m_name); this->m_age = p.m_age; return *this; } ~Person() { if (this->m_name != NULL) { delete[] this->m_name; this->m_name = NULL; } } char* m_name; int m_age; private:}; //编译器 默认给一个类添加了4个函数默认构造 析构 拷贝构造(值拷贝) operator void test01() { Person p1("Tom",10); p1.m_age = 10; //Person p2 = p1; //拷贝构造函数 Person p2("Jerry",19); p2 = p1; cout << p2.m_name << endl; cout << p2.m_age << endl; Person p3("Jerry", 19); p3 = p2 = p1; //这是赋值 Person p4 = p3; //这是拷贝构造 cout << p3.m_name << endl; cout << p3.m_age << endl; } []重载 int& operator[](int index); //index 为索引值 int& operator[](int index) { return this->pAddress[index]; } arr[0]=1000; //左值时得返回有空间的值,即引用 关系运算符很重要 小技巧:返回值是bool类型可以 return (this->m_name == p.m_name && this->m_age == p.m_age); //替代下边判断//if(this->m_name == p.m_name && this->m_age == p.m_age)// {// return true; //}//return false; //关系运算符 class Person { public: Person(){}; Person(string name,int age) { this->m_name = name; this->m_age = age; } bool operator==(Person &p) { return (this->m_name == p.m_name && this->m_age == p.m_age); //替代下边判断 //if(this->m_name == p.m_name && this->m_age == p.m_age) // { // return true; //} //return false; } bool operator!=(Person& p) { return!(this->m_name == p.m_name && this->m_age == p.m_age); } ~Person(){}; string m_name; int m_age; private:}; void test01() { int a = 10; int b = 20; if (a == b) { cout << "a==b" << endl; } else { cout << "a!=b" << endl; } Person p1("TOM", 18); Person p2("TOM", 18); if (p1 == p2) { cout << "p1==p2" << endl; } else { cout << "p1!=p2" << endl; } if (p1 != p2) { cout << "p1!=p2" << endl; } else { cout << "p1==p2" << endl; } } 函数调用运算符重载 MyAdd()(1, 1)//匿名函数对象 仿函数实际重载() class MyPrint { public: MyPrint(){}; void operator()(string text) { cout << text << endl; } ~MyPrint(){}; private:}; void test01() { MyPrint my_printf; my_printf("hello world"); //仿函数,函数对象 }class MyAdd { public: MyAdd(){}; int operator()(int a, int b) { return a + b; } ~MyAdd(){}; private: }; void test02() { MyAdd my_add; cout << my_add(1, 1) << endl; cout << MyAdd()(1, 1) << endl; //匿名函数对象,当前行执行完自动释放 } 不要重载逻辑运算符&&和|| 因为有短路特性 &&左边为假右边将不计算||左边为真右边不用算 0&&11||0 无法重载原有预期,会与运算优先级结合会影响到左边

十九、强化训练字符封装
MyString.h #pragma once #define _CRT_SECURE_NO_WARNINGS #include using namespace std; class MyString { //重载左移运算符 friend ostream& operator<<(ostream& cout, MyString& str); //重载右移运算符 friend istream& operator>>(istream& cin, MyString& str); public: MyString(); MyString(const char* str) ; MyString(const MyString& str) ; //重载=运算符 MyString& operator=(const char* str); MyString& operator=(const MyString& str); //重载运算符[] char& operator[](int index); //重载+运算符 MyString operator+(const char* str); MyString operator+(const MyString& str); //重载== bool operator==(const char* str); bool operator==(const MyString& str); ~MyString(); private: char* pString; //维护在堆区开辟的字符数组 int m_size; //字符串长度 不统计\0 }; MyString.cpp #include "MyString.h"MyString::MyString() {}MyString::MyString(const char* str) { /*cout << "有参构造函数调" << endl; */ this->pString = new char[strlen(str) + 1]; strcpy(this->pString, str); this->m_size = strlen(str); }MyString::MyString(const MyString& str) { /*cout << "拷贝构造函数调" << endl; */ this->pString = new char[strlen(str.pString)+1]; strcpy(this->pString, str.pString); this->m_size = str.m_size; }MyString& MyString::operator=(const char* str) { // 先判断原来堆区释放原有内容,如果有先释放 if (this->pString != NULL) { delete[] this->pString; this->pString = NULL; } this->pString = new char[strlen(str) + 1]; strcpy(this->pString, str); this->m_size = strlen(str); return *this; }MyString& MyString::operator=(const MyString& str) { if (this->pString != NULL) { delete[] this->pString; this->pString = NULL; } this->pString = new char[strlen(str.pString) + 1]; strcpy(this->pString, str.pString); this->m_size = str.m_size; return *this; }char& MyString::operator[](int index) { return this->pString[index]; }MyString MyString::operator+(const char* str) { int NewSize = this->m_size + strlen(str) + 1; char* temp = new char[NewSize]; memset(temp, 0, NewSize); strcat(temp, this->pString); strcat(temp, str); MyString NewString = temp; delete[] temp; return NewString; }MyString MyString::operator+(const MyString& str) { int NewSize = this->m_size + strlen(str.pString) + 1; char* temp = new char[NewSize]; memset(temp, 0, NewSize); strcat(temp, this->pString); strcat(temp, str.pString); MyString NewString = temp; delete[] temp; return NewString; }bool MyString::operator==(const char* str) { /*return (this->pString == str); *///不可以 return (strcmp(this->pString, str) == 0); }bool MyString::operator==(const MyString& str) { return (strcmp(this->pString, str.pString) == 0); }MyString::~MyString() { /*cout << "析构函数调" << endl; */ if (this->pString != NULL) { delete[] this->pString; } }ostream& operator<<(ostream &cout,MyString &str) { cout << str.pString; return cout; }istream& operator>>(istream& cin, MyString& str) { if (str.pString != NULL)//if (str.pString) { delete[] str.pString; str.pString = NULL; } char buf[1024]; cin >> buf; str.pString = new char[strlen(buf) + 1]; strcpy(str.pString, buf); str.m_size = strlen(buf); return cin; } test.cpp #define _CRT_SECURE_NO_WARNINGS #include #include "MyString.h" using namespace std; void test01() { MyString str = "arr"; MyString str2 = str; cout << str <> str; cout << "str新的值" << str << endl; }void test02() { MyString str = "arr"; MyString str2 = "aaa"; str2 = str; cout << "str2 = " << str2 << endl; str2[0] = 'z'; cout << str2[0] << endl; MyString str3 = "abc"; MyString str4 = "def"; MyString str5 = str3 + str4; MyString str6 = str3 + str4 + str5; cout << "str5: " << str5 << endl; cout << "str6: " << str6 << endl; if (str5 == str6) { cout << "str5==str6" << endl; } else { cout << "str5!=str6" << endl; } str6 = "abcd"; if (str6 == "abcd") { cout << "str6==" << endl; } else { cout << "!=str6" << endl; } }int main(int argc, char* argv[]) { test02(); system("pause"); return EXIT_SUCCESS; }

二十、继承
#include using namespace std; //class News //{ //public: // // void header() // { //cout << "公共的头部" << endl; // } // // void footer() // { //cout << "公共的底部" << endl; // } // // void leftList() // { //cout << "公共左侧列表" << endl; // } // // void content() // { //cout << "新闻播报..." << endl; // } //}; //利用继承模拟网页 //继承优点: 减少重复代码,提高代码复用性 //子类可以访问:public protected不可访问:private class BasePage { public: void header() { cout << "公共的头部" << endl; } void footer() { cout << "公共的底部" << endl; } void leftList() { cout << "公共左侧列表" << endl; }}; class News : public BasePage { public: void content() { cout << "新闻播报..." << endl; } }; class Sport : public BasePage { public : void content() { cout << "世界杯..." << endl; } }; void test01() { News news; cout << "新闻页面为: " << endl; news.header(); news.footer(); news.leftList(); news.content(); }

笔记分享|C++学习笔记(B站黑马程序员C++教程)
文章图片

#include using namespace std; /********************公共继承********************/ class Base1 { /*friend class Son1 ; */ //子类可以作为父类的友元 public: int m_a; protected: int m_b; private: int m_c; }; class Son1 : public Base1 { public: void func() { m_a = 100; //父类中 公共权限 子类中变为 公共权限 m_b = 100; //父类中 保护权限 子类中变为 保护权限 //m_c = 100; //父类中私有成员,子类无法访问 } }; void test01() { Son1 s1; s1.m_a = 100; /*s1.m_b = 100; */ //在类外不可访问 }/********************保护继承********************/ class Base2 { public: int m_a; protected: int m_b; private: int m_c; }; class Son2 : protected Base2 { public: void func() { m_a = 100; //父类中 公共权限 子类中变为 公共权限 m_b = 100; //父类中 保护权限 子类中变为 保护权限 //m_c = 100; //父类中私有成员,子类无法访问 } }; void tes02() { Son2 s2; //父类继承过来的全变成保护权限 /*s1.m_a = 100; *///在类外不可访问 /*s1.m_b = 100; */ //在类外不可访问 }/********************私有继承********************/ class Base3 { public: int m_a; protected: int m_b; private: int m_c; }; class Son3 : private Base3 { public: void func() { m_a = 100; //父类中 公共权限 子类中变为 公共权限 m_b = 100; //父类中 保护权限 子类中变为 保护权限 //m_c = 100; //父类中私有成员,子类无法访问 } }; void tes03() { Son3 s3; //父类继承过来的全变成私有权限 /*s1.m_a = 100; *///在类外不可访问 /*s1.m_b = 100; */ //在类外不可访问 }class GrandSon3 : public Son1// Son1Son2可以继承因为父类是公共权限和保护权限//Son3不能是私有权限 { public: void func() { m_a = 100; } }; int main(int argc, char* argv[]) { system("pause"); return EXIT_SUCCESS; }

笔记分享|C++学习笔记(B站黑马程序员C++教程)
文章图片

继承中的对象 父类的私有属性,子类是继承下去了,只不过是编译器给隐藏了,访问不到 可以利用开发人员工具查看对象模型 D:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools 打开开发人员命令工具 跳转盘符 D: 跳转文件路径cd \Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools cl/d1 reportSingleClassLayou类名 继承中的构造和析构 //先调用父类构造,再调用其他成员构造,再构造自身 //先调用父类构造,再调用其他成员构造,再构造自身 //子类继承默认调用父类无参构造函数,如父类定义有参构造,父类需定义无参构造函数 或者 子类用列表初始化 //父类中的 默认构造、析构、拷贝构造、operator= 是不会被子类继承下去,但是会调用 #include using namespace std; class Base1 { public: Base1() { cout << "Base1的构造函数调用" << endl; } ~Base1() { cout << "Base1的析构函数的调用" << endl; } }; class Other { public: Other() { cout << "Other的构造函数调用" << endl; } ~Other() { cout << "Other的析构函数的调用" << endl; } }; class Son1 : public Base1 { public : Son1() { cout << "Son1的构造函数调用" << endl; } ~Son1() { cout << "Son1的析构函数的调用" << endl; } Other other; }; void test01() { Son1 s; //先调用父类构造,再调用其他成员构造,再构造自身 }class Base2 { public: Base2(int a) { this->m_a = a; cout << "Base2的构造函数调用" << endl; } int m_a; }; //子类继承默认调用父类无参构造函数,如父类定义有参构造,父类需定义无参构造函数 //或者 子类用列表初始化 class Son2 : public Base2 { public: Son2(int a):Base2(a) //利用初始化列表语法 显示调用父类中的其他构造函数 { cout << "Son2的构造函数调用" << endl; } }; void test02() { Son2 s(100); cout << s.m_a << endl; }//父类中的 默认构造、析构、拷贝构造、operator= 是不会被子类继承下去,但是会调用int main(int argc, char* argv[]) { test02(); system("pause"); return EXIT_SUCCESS; } 继承中同名成员处理 //1.我们可以利用作用域访问父类的同名成员 //2.当子类重新定义了父类中的同名成员函数,子类的成员函数会隐藏掉父类中所有的重载版本 可以用作用域访问 #include using namespace std; class Base { public: Base() { this->m_a = 10; } void func() { cout << "func父类调用" << endl; } void func(int a) { cout << "func (int a)调用" << endl; } int m_a; }; class Son : public Base { public: Son() { this->m_a = 20; } void func() { cout << "func子类调用" << endl; } int m_a; }; void test01() { Son s1; cout << "s1.m_a = " << s1.m_a << endl; //我们可以用作用域访问父类中的同名成员 cout << "Base中的m_a = " << s1.Base::m_a << endl; }void test02() { Son s1; s1.func(); s1.Base::func(); /*s1.func(10); *///不能用 //当子类重新定义了父类中的同名成员函数,子类的成员函数会隐藏掉父类中所有的重载版本 //可以用作用域访问 //改为 s1.Base::func(10); }int main(int argc, char* argv[]) { test02(); system("pause"); return EXIT_SUCCESS; } 继承中的同名的静态成员 当子类重定义父类中同名的成员函数,子类的成员函数会隐藏掉父类中的所有版本,需要加作用域调用 #include using namespace std; class Base { public: static void func()//没有this指针 { cout << "Base中的func()调用" << endl; } static void func(int a)//没有this指针 { cout << "父类中的func(int a )调用" << endl; } static int m_a; }; int Base::m_a = 10; class Son : public Base { public: static void func()//没有this指针 { cout << "子类中的func()调用" << endl; } static void func(int a)//没有this指针 { cout << "子类中的func(int a )调用" << endl; } static int m_a; }; int Son::m_a = 20; //测试继承静态同名成员变量 void test01() { //1.通过对象访问 Son s; cout << "m_a = " << s.m_a << endl; cout << "Base m_a = " << s.Base::m_a << endl; //2.通过类名访问 cout << "m_a = " << Son::m_a << endl; cout << "Base m_a = " << Base::m_a << endl; //通过类名的方式从子类到父类访问 cout << "Base m_a = " << Son::Base::m_a << endl; }//测试继承静态同名成员函数 //当子类重定义父类中同名的成员函数,子类的成员函数会隐藏掉父类中的所有版本,需要加作用域调用 void test02() { //1.通过对象访问 Son s; s.func(); s.Base::func(); //2.通过类名访问 Son::func(); Base::func(); Son::Base::func(); Son::func(1); //当子类重定义父类中同名的成员函数,子类的成员函数会隐藏掉父类中的所有版本,需要加作用域调用 Son::Base::func(1); }int main(int argc, char* argv[]) { test02(); system("pause"); return EXIT_SUCCESS; }

继承的概念 多继承
笔记分享|C++学习笔记(B站黑马程序员C++教程)
文章图片

vbptrv-virtual 虚拟 b base基础 ptr pointer 指针//vbtable虚基类表,加上virtual 实质是通过指针在虚基类表上偏移,找到同一指向地址 class A:public B1,public B2#include using namespace std; //动物类//Animal称为虚基类 class Animal { public: int m_age; //年龄 }; //羊类 class Sheep : virtual public Animal { public:}; //驼类 class Tuo : virtual public Animal { public:}; //驼类虚继承 class SheepTuo : public Sheep, public Tuo {}; void test01() { SheepTuo st; st.Sheep::m_age = 10; st.Tuo::m_age = 20; cout << "shee::m_age = " << st.Sheep::m_age << endl; cout << "shee::m_age = " << st.Tuo::m_age << endl; cout << "shee::m_age = " << st.m_age << endl; //当虚继承后,sheep和tuo类中继承了一个 vbptr指针 虚基类指针 指向的是一个虚基类表 vbtable //虚基类表中记录了 偏移量,通过偏移量可以找到唯一的一个m_age}void test02() { SheepTuo st; st.m_age = 10; //通过Sheep找到偏移量 //*(int *)&st 解引用到了 虚基类表中 cout << *((int*)*(int*)&st + 1) << endl; //通过tuo找到偏移量 cout << *((int*)*((int*)&st + 1)+1 ) << endl; //通过偏移量 访问m_age cout << "m_age = " << ((Animal*)((char*)&st + *((int*)*(int*)&st + 1)))->m_age << endl; cout << "m_age = " << *((int*)((char*)&st + *((int*)*(int*)&st + 1))) << endl; }int main(int argc, char* argv[]) { test02(); system("pause"); return EXIT_SUCCESS; }

视频链接https://www.bilibili.com/video/BV1kV411U7Ub?spm_id_from=333.999.0.0
【笔记分享|C++学习笔记(B站黑马程序员C++教程)】建议用python或者浏览器视频插件把视频先下下来,万一没了呢!!!

    推荐阅读