发布时间:2024-06-04 16:01
视频链接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;*///非静态成员只能对应某个对象访问
}
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_num = 0;
};
//前置++重载
MyInter& operator++()
{
++this->m_num;
return *this;
}
//后置++重载
MyInter operator++(int)//加int 占位编译器自动识别
{
//先记录初始状态
MyInter temp = *this;
this->m_num++;
return temp;
}
~MyInter(){};
private:
int m_num;
/*int m_temp;*/
};
ostream& operator<<(ostream& cout, MyInter& myint) {
cout << myint.m_num;
return cout;
}
void test01() {
MyInter my_inter;
cout << ++(++my_inter) << endl;
cout << my_inter << endl;
my_inter++;
//cout << my_inter++ << endl;
}
指针运算符重载
智能指针,本质是存在堆空间,利用栈自动释放本身,释放堆空间,减小栈空间的使用
class Person
{
public:
Person(int age)
{
cout << \"Person的有参构造调用\" << endl;
this->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&&1 1||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();
}
#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 // Son1 Son2可以继承因为父类是公共权限和保护权限 //Son3 不能是私有权限
{
public:
void func()
{
m_a = 100;
}
};
int main(int argc, char* argv[])
{
system(\"pause\");
return EXIT_SUCCESS;
}
继承中的对象
父类的私有属性,子类是继承下去了,只不过是编译器给隐藏了,访问不到
可以利用开发人员工具查看对象模型
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;
}
继承的概念 多继承
vbptr v-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
建议用python或者浏览器视频插件把视频先下下来,万一没了呢!!!