c++学习
类与对象
重载
赋值运算符重载
1 #include <iostream> 2 using namespace std; 3 4 //赋值运算符重载 5 6 class Person 7 { 8 public: 9 10 int *m_Age; 11 12 Person(int age) 13 { 14 m_Age = new int(age); 15 } 16 17 ~Person() 18 { 19 if(m_Age != NULL) 20 { 21 delete m_Age; 22 m_Age = NULL; 23 } 24 } 25 26 //重载赋值运算符 27 Person& operator=(Person &p) 28 { 29 //编译器提供浅拷贝 30 31 //判断是否有属性在堆区,如果有,就先释放干净再深拷贝 32 if(m_Age != NULL) 33 { 34 delete m_Age; 35 m_Age = NULL; 36 } 37 38 //深拷贝 39 m_Age = new int(*p.m_Age); 40 41 //返回对象自身 42 return *this; 43 } 44 45 }; 46 47 48 void test01() 49 { 50 Person p1(18); 51 cout << "年龄:" << *p1.m_Age << endl; 52 53 Person p2(20); 54 55 //赋值操作,相当于浅拷贝,会触发double free的操作 56 p2 = p1; 57 58 cout << "年龄:" << *p2.m_Age << endl; 59 60 } 61 62 int main() 63 { 64 test01(); 65 }
关系运算符重载
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 //重载关系运算符 6 7 class Person 8 { 9 public: 10 Person(string name,int age) 11 { 12 m_Name = name; 13 m_Age = age; 14 } 15 16 //重载 == 号 17 bool operator==(Person &p) 18 { 19 if(this -> m_Name == p.m_Name and this -> m_Age == p.m_Age) 20 { 21 return true; 22 } 23 else 24 return false; 25 } 26 27 28 public: 29 string m_Name; 30 int m_Age; 31 }; 32 33 34 void test01() 35 { 36 Person p1("tom",18); 37 Person p2("tom",18); 38 39 if(p1 == p2) 40 cout << "p1和p2相等" << endl; 41 else 42 cout << "p1和p2不相等" << endl; 43 } 44 45 int main() 46 { 47 test01(); 48 }
函数调用运算符重载
- 函数调用运算符()也可以重载
- 称为仿函数:在类中重载了小括号
- 调用非常灵活
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 //重载函数调用运算符 6 7 class myAdd 8 { 9 public: 10 11 //函数调用运算符重载 12 int operator()(int a,int b) 13 { 14 return a+b; 15 } 16 }; 17 18 int myadd(int a,int b) 19 { 20 return a+b; 21 } 22 23 void test01() 24 { 25 myAdd add1; 26 int ret = add1(1,2); 27 cout << "仿函数返回:" << ret << endl; 28 int ret1 = myadd(1,2); 29 cout << "真实函数返回:" << ret1 << endl; 30 } 31 32 int main() 33 { 34 test01(); 35 }
继承
继承是面向对象三大特性之一
作用:可减少重复代码
继承基本语法
在一个网页中许多信息都是重复的,比如顶部信息,底部信息和侧边栏,所以我们可用继承的方式来写
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 //继承好处:减少重复代码 6 //语法 class 子类: 继承方式 父类 7 // 子类 == 派生类 8 // 父类 == 基类 9 10 class PageBase 11 { 12 public: 13 void top_page() 14 { 15 cout << "网页的顶部信息" << endl; 16 } 17 void bottom_page() 18 { 19 cout << "网页的底部信息" << endl; 20 } 21 void left_page() 22 { 23 cout << "网页的侧边栏信息" << endl; 24 } 25 }; 26 27 class Main_Page : public PageBase 28 { 29 public: 30 void content() 31 { 32 cout << "主页面中独有的信息" << endl; 33 } 34 }; 35 36 class Second_Page : public PageBase 37 { 38 public: 39 void content() 40 { 41 cout << "第二页中独有的信息" << endl; 42 } 43 }; 44 45 46 int main() 47 { 48 Main_Page p1; 49 p1.top_page(); 50 p1.bottom_page(); 51 p1.left_page(); 52 p1.content(); 53 54 Second_Page p2; 55 p2.top_page(); 56 p2.bottom_page(); 57 p2.left_page(); 58 p2.content(); 59 }
继承方式
继承方式一共有三种
- 公共继承:父类中的啥属性到子类中不变,比如public还是public,protect还是protect
- 保护继承:父类中的所有权限到子类都变成了保护权限
- 私有继承:父类中的所有权限到子类都变成了私有权限
无论哪种继承方式都无法访问父类中的private的东西
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 class Base 6 { 7 public: 8 int m_A; 9 protected: 10 int m_B; 11 private: 12 int m_C; 13 }; 14 15 class Son1:public Base 16 { 17 public: 18 19 void func() 20 { 21 m_A = 10; 22 m_B = 10; 23 //m_C = 10; 24 } 25 26 }; 27 28 class Son2:protected Base 29 { 30 public: 31 32 void func() 33 { 34 m_A = 10; 35 m_B = 10; 36 //m_C = 10; 37 } 38 // 在该类中所有的属性都是protected属性 39 }; 40 41 class Son3:private Base 42 { 43 public: 44 45 void func() 46 { 47 m_A = 10; 48 m_B = 10; 49 //m_C = 10; 50 } 51 // 在该类中所有的属性都是private属性 52 }; 53 54 55 int main() 56 { 57 Son1 s_public; 58 s_public.m_A = 10; 59 //s_public.m_B = 10; 60 61 Son2 s_protected; 62 //s_protected.m_A = 10; 63 }
继承中的对象模型
问题:从父类继承过来的成员,哪些属于子类对象中?
1 #include <iostream> 2 using namespace std; 3 4 // 继承中的对象模型 5 6 class Base 7 { 8 public: 9 int m_A; 10 protected: 11 int m_B; 12 private: 13 int m_C; 14 }; 15 16 class Son:public Base 17 { 18 public: 19 int m_D; 20 }; 21 22 void test() 23 { 24 25 // 16:在父类中非静态成员属性都会被子类继承下去 26 // 虽然私有属性无法访问,但是也被继承了 27 cout << "size of Son:" << sizeof(Son) << endl; 28 } 29 30 int main() 31 { 32 test(); 33 }
继承中构造和析构顺序
子类继承父类后,当创建子类对象,也会调用父类的构造函数
问题:父类和子类的构造函数谁先谁后?
1 #include <iostream> 2 using namespace std; 3 4 // 继承中的构造函数,和析构函数 顺序 5 6 class Base 7 { 8 public: 9 Base() 10 { 11 cout << "Base的构造函数" << endl; 12 } 13 ~Base() 14 { 15 cout << "Base的析构函数" << endl; 16 } 17 }; 18 19 class Son:public Base 20 { 21 public: 22 Son() 23 { 24 cout << "Son的构造函数" << endl; 25 } 26 ~Son() 27 { 28 cout << "Son的析构函数" << endl; 29 } 30 }; 31 32 void test() 33 { 34 Son s1; 35 } 36 37 int main() 38 { 39 test(); 40 }
继承同名成员处理方式
1 #include <iostream> 2 using namespace std; 3 4 // 继承中的构造函数,和析构函数 顺序 5 6 class Base 7 { 8 public: 9 Base() 10 { 11 m_A = 100; 12 } 13 void func() 14 { 15 cout << "Base中的func调用" << endl; 16 } 17 18 public: 19 int m_A; 20 }; 21 22 class Son:public Base 23 { 24 public: 25 Son() 26 { 27 m_A = 200; 28 } 29 void func() 30 { 31 cout << "Son中的func调用" << endl; 32 } 33 public: 34 int m_A; 35 }; 36 37 //同名属性处理方式 38 void test1() 39 { 40 Son s1; 41 // 如果出现同名成员,默认调用子类的成员,如果要调用父类,则要加作用域 42 cout << "m_A = " << s1.m_A << endl ; 43 cout << "m_A = " << s1.Base::m_A << endl; 44 } 45 46 // 同名函数处理方式 47 void test2() 48 { 49 Son s2; 50 s2.func(); 51 // 如果子类中出现和父类中同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数(包括重载的) 52 // 如果想访问父类的成员函数,则必须加作用域 53 s2.Base::func(); 54 } 55 56 int main() 57 { 58 test1(); 59 test2(); 60 }
总结
- 子类对象可以直接访问到子类中同名成员
- 子类对象加作用域可以访问到父类对象的同名成员
- 如果子类中出现和父类中同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数(包括重载的)
继承同名静态成员处理方式
同非静态的成员处理方法一样
1 #include <iostream> 2 using namespace std; 3 4 5 6 class Base 7 { 8 public: 9 static int m_A; 10 static void func() 11 { 12 cout << "Base static func" << endl; 13 } 14 }; 15 16 int Base::m_A = 100; // 定义静态成员属性在类外必须初始化,且所有对象共享这个静态成员属性 17 18 19 class Son:public Base 20 { 21 public: 22 static int m_A; 23 static void func() 24 { 25 cout << "Son static func" << endl; 26 } 27 }; 28 29 int Son::m_A = 200; 30 31 //同名静态属性 32 void test1() 33 { 34 Son s1; 35 cout << "通过对象访问:" << endl; 36 cout << "Son下静态成员属性" << s1.m_A << endl; 37 cout << "Base下静态成员属性" << s1.Base::m_A << endl; 38 39 cout << "通过类名访问:" << endl; 40 cout << "Son下静态成员属性" << Son::m_A << endl; 41 // 第一个双冒号:代表通过类名访问,第二个双冒号:代表访问父类作用域下 42 cout << "Base下静态成员属性" << Son::Base::m_A << endl; 43 } 44 45 46 //同名静态函数 47 void test2() 48 { 49 Son s1; 50 s1.func(); 51 s1.Base::func(); 52 53 Son::func(); 54 Son::Base::func(); 55 } 56 57 int main() 58 { 59 //test1(); 60 test2(); 61 62 }
多继承语法
c++允许一个类继承多个类
语法:class 子类:继承方式 父类1,继承方式 父类2……
菱形继承
概念:
两个派生类继承同一个基类
又有某个类同时继承这两个派生类
菱形继承问题:
1,两个派生类继承了基类的数据,当派生类的子类使用数据时,会引发二义性
2,子类的子类继承基类,继承了两份数据,其实只需要一份就可以了
多态
多态的基本概念与语法
多态是c++面向对象三大特性之一
多态分类
- 静态多态:函数重载和运算符重载属于静态多态,复用函数名
- 动态多态:派生类和虚函数实现运行时多态
区别:静态多态编译阶段就确定函数地址,动态多态运行时才确定
1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 5 class Animal 6 { 7 public: 8 void speak() 9 { 10 cout << "动物在说话" << endl; 11 } 12 }; 13 14 class Cat : public Animal 15 { 16 public: 17 void speak() 18 { 19 cout << "小猫在说话" << endl; 20 } 21 }; 22 23 void doSpeak(Animal &animal) // Animal &animal = cat; 24 { 25 26 animal.speak(); 27 // 运行结果是动物在说话 原因:地址早绑定,无论传什么动物都是动物在说话 28 // 要想猫在说话,就需要地址晚绑定 29 } 30 31 void test01() 32 { 33 Cat cat; 34 doSpeak(cat); 35 } 36 37 int main() 38 { 39 test01(); 40 }
1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 5 class Animal 6 { 7 public: 8 virtual void speak() // 虚函数,地址晚绑定 9 { 10 cout << "动物在说话" << endl; 11 } 12 }; 13 14 class Cat : public Animal 15 { 16 public: 17 // 重写概念:函数返回值类型,函数名,形参列表完全相同 18 // 子类中的virtual可写可不写 19 void speak() 20 { 21 cout << "小猫在说话" << endl; 22 } 23 }; 24 25 // 动态多态满足条件: 26 // 1,有继承关系 27 // 2,子类重写父类的虚函数 28 29 // 多态使用方法:父类的指针或者引用,指向子类对象 30 31 void doSpeak(Animal &animal) // Animal &animal = cat; 32 { 33 34 animal.speak(); 35 } 36 37 void test01() 38 { 39 Cat cat; 40 doSpeak(cat); 41 } 42 43 int main() 44 { 45 test01(); 46 }