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_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&&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();
}
文章图片
#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;
}
文章图片
继承中的对象
父类的私有属性,子类是继承下去了,只不过是编译器给隐藏了,访问不到
可以利用开发人员工具查看对象模型
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;
}
继承的概念 多继承
文章图片
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或者浏览器视频插件把视频先下下来,万一没了呢!!!
推荐阅读
- c++|【b站黑马程序员C++视频学习笔记-继承的基本语法】
- c++|C++实现之单链表中删除指定值
- python|Python学习笔记(3)---B站黑马程序员
- python练习题|python基础20道小练习
- 单片机stm32|学习单片机切记这四点要求,少走弯路
- 业界资讯|TIOBE 5 月编程语言排行榜(C# 最受开发者欢迎,C++ 将冲击 Top 3)
- leetcode|力扣刷题 16.合并两个有序数组——简单题
- 慕课网/安卓攻城狮视频学习及练习
- 慕课网/安卓攻城狮视频学习及练习——简陋计算器