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

发布时间:2024-06-04 16:01

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&&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();

}

\"C++学习笔记(B站黑马程序员C++教程)_第1张图片\"

#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;
}

\"C++学习笔记(B站黑马程序员C++教程)_第2张图片\"

继承中的对象
父类的私有属性,子类是继承下去了,只不过是编译器给隐藏了,访问不到
可以利用开发人员工具查看对象模型
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++教程)_第3张图片\"

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或者浏览器视频插件把视频先下下来,万一没了呢!!!

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号