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 }
View Code

关系运算符重载

 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 }
View Code

函数调用运算符重载

  • 函数调用运算符()也可以重载
  • 称为仿函数:在类中重载了小括号
  • 调用非常灵活
 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 }
View Code

继承

继承是面向对象三大特性之一

作用:可减少重复代码

继承基本语法

在一个网页中许多信息都是重复的,比如顶部信息,底部信息和侧边栏,所以我们可用继承的方式来写

 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 }
View Code

继承方式

继承方式一共有三种

  • 公共继承:父类中的啥属性到子类中不变,比如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 }
View Code

继承中的对象模型

问题:从父类继承过来的成员,哪些属于子类对象中?

 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 }
View Code

继承中构造和析构顺序

子类继承父类后,当创建子类对象,也会调用父类的构造函数

问题:父类和子类的构造函数谁先谁后?

 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 }
View Code

继承同名成员处理方式

 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 }
View Code

总结

  1. 子类对象可以直接访问到子类中同名成员
  2. 子类对象加作用域可以访问到父类对象的同名成员
  3. 如果子类中出现和父类中同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数(包括重载的)

继承同名静态成员处理方式

同非静态的成员处理方法一样

 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 }
View Code

多继承语法

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 }
View Code
 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 }
View Code
原文地址:https://www.cnblogs.com/lemon629/p/13806210.html