zoukankan      html  css  js  c++  java
  • <C++> 类(3):初始化列表 常函数和常量对象 虚函数与多态(包括纯虚函数)

    一.初始化列表(初始化列表中必须有的两个内容)

    1.类中const的成员变量

    ①特点:不能修改 必须初始化 在构造函数后面加冒号 格式为:“:变量名(值)”

    也就是说 常量必须在初始化列表中初始化

    ②执行顺序:构造函数先执行初始化列表 然后执行函数中的内容

     1 #include<iostream>
     2 using namespace std;
     3 
     4 class CPerson
     5 {
     6 public:
     7     const int a;
     8 public:
     9     CPerson():a(100)
    10     {
    11 
    12     }
    13     void Show()
    14     {
    15         cout << a << endl;
    16     }
    17 };
    18 
    19 int main()
    20 {
    21     CPerson ps;
    22     ps.Show();
    23 
    24     return 0;
    25 }

    2.组合关系的类中的构造函数有参数

    ①例:包含了另一个类的对象要执行指定的构造函数

     1 #include<iostream>
     2 using namespace std;
     3 
     4 class CHead
     5 {
     6 public:
     7     CHead(int a)
     8     {
     9 
    10     }
    11 };
    12 
    13 class CPerson
    14 {
    15 public:
    16     CHead head;
    17 public:
    18     CPerson():head(100)
    19     {
    20 
    21     }
    22 };
    23 
    24 int main()
    25 {
    26     CPerson ps;
    27 
    28     return 0;
    29 }

    二.const常函数和常量对象

    1.常函数:

    ①基本格式:void Show() const{ .. }

    ②特点:不能修改类中的成员变量

    可以理解为 常函数参数括号中传的指针已经变成const CPerson* this这种指针了(拿CPerson为例)

    也就是说 this已经变成const类型 这种指针的指向是不可以修改的 但是可以使用

    2.常量对象:

    ①格式:const CPerson ps;

    ②特点:常量对象只能调用常函数 不能使用普通函数

    可以理解为ps.Show(const CPerson*); 传入对象的地址类型不可改变

    下面是一个常函数和常量函数的简单例子:

     1 #include<iostream>
     2 using namespace std;
     3 
     4 class CPerson
     5 {
     6 public:
     7     int m_nAge;
     8 public:
     9     CPerson()
    10     {
    11         m_nAge = 100;
    12     }
    13 public:
    14     void Show() const 
    15     {
    16         cout << m_nAge << endl;
    17     }
    18     void Show1()
    19     {
    20         m_nAge = 200;
    21         cout << m_nAge << endl;
    22     }
    23 };
    24 
    25 int main()
    26 {
    27     const CPerson ps;
    28     CPerson ps1;
    29     ps.Show();
    30     ps1.Show1();
    31 
    32     return 0;
    33 }

    三.虚函数与多态

    1.引入:

    ①重载:同名 参数列表不同 调用父类的内容时要加作用域

    ②重写:同名 参数列表相同 全一致

    ③隐藏:是纵向重载 只要同名就好

    2.父类的指针指向子类的对象

    ①例如:CFather* pFather = new CSon;

    ②注意:这类指针只能看到父类的东西 但是子类的指针不能指向父类的对象

    3.虚函数与多态:利用父类的复用性 充当接口类

    ①虚函数:virtual

    作用:通过父类的指针调用子类的函数

    注意:虚函数实现多态是基于重写来实现的 这使父类的指针具有多种形态

    如果子类中重写了父类的函数 那么在虚函数列表中父类就被子类所覆盖

    覆盖基于虚函数的重写 重写在子类中进行重写

     1 #include<iostream>
     2 using namespace std;
     3 
     4 class CWater
     5 {
     6 public:
     7     virtual void Show()
     8     {
     9         cout << "CWater::Show()" << endl; 
    10     }
    11 };
    12 
    13 class CMilk : public CWater
    14 {
    15 public:
    16     void Show()
    17     {
    18         cout << "CMilk::Show()" << endl;
    19     }
    20 };
    21 
    22 class CBeer : public CWater
    23 {
    24 public:
    25     void Show()
    26     {
    27         cout << "CBeer::Show()" << endl;
    28     }
    29 };
    30 
    31 void Bottle(CWater* cw)
    32 {
    33     cw -> Show();
    34 }
    35 
    36 int main()
    37 {
    38     CMilk cm;
    39     CBeer cb;
    40 
    41     Bottle(&cm);
    42     Bottle(&cb);
    43 
    44     return 0;
    45 }

    ②多态:

    用父类的指针指向子类 通过父类的指针调用子类成员函数

     1 #include<iostream>
     2 using namespace std;
     3 
     4 class CFather
     5 {
     6 public:
     7     virtual void AA()
     8     {
     9         cout << "CFather::AA()" << endl;
    10     }
    11     virtual void BB()
    12     {
    13         cout << "CFather::BB()" << endl;
    14     }
    15     void CC()
    16     {
    17         cout << "CFather::CC()" << endl;
    18     }
    19 };
    20 
    21 class CSon : public CFather
    22 {
    23 public:
    24     virtual void AA()
    25     {
    26         cout << "CSon::AA()" << endl;
    27     }
    28     void CC()
    29     {
    30         cout << "CSon::CC()" << endl;
    31     }
    32     void DD()
    33     {
    34         cout << "CSon::DD()" << endl;
    35     }
    36 };
    37 
    38 int main()
    39 {
    40     CFather* cf1 = new CSon;
    41 
    42     cf1 -> AA();
    43     cf1 -> BB();
    44     cf1 -> CC();
    45 
    46     return 0;
    47 }

    4.(感觉上面整理的好乱)总结虚函数与多态

    ①什么是多态:

    父类的指针指向一个子类的对象 通过父类的指针调用实际子类的成员函数 这样才会使父类指针具有多种形态

    ②多态基于什么实现:

    多态基于虚函数 虚函数基于重写

    ③多态的实现原理:虚函数列表和虚指针

    在虚函数列表中 表中的每个元素都是一个函数指针 指向虚函数 或重写的虚函数

    虚函数列表是在编译的时候就存在的 每一个类都有一个(对于普通的单继承来说)

    虚指针就是记录使用哪一个列表的指针 在构造函数中被初始化 指向子类虚函数列表 这个指针是一个类成员

    虚指针在创建对象的时候存在 在这个对象的首地址的前4个字节就是这个指针

    那么我们就可以把调用一个虚函数理解为:通过虚指针拿到虚函数列表中的函数指针来实现调用的

    ④优缺点:

    优点就是提高了复用性 扩展性

    缺点就是安全性比较低 空间和效率问题也比较差

    最后再放一个典型的例子加深理解:这段代码的输出足以说明这个问题

     1 #include<iostream>
     2 using namespace std;
     3 
     4 class CFather
     5 {
     6 public:
     7     void AA()
     8     {
     9         cout << "CFather::AA()" << endl;
    10     }
    11     virtual void BB()
    12     {
    13         cout << "CFather::BB()" << endl;
    14     }
    15 };
    16 
    17 class CSon : public CFather
    18 {
    19 public:
    20     void AA()
    21     {
    22         cout << "CSon::AA()" << endl;
    23     }
    24     virtual void BB()
    25     {
    26         cout << "CSon::BB()" << endl;
    27     }
    28 };
    29 
    30 int main()
    31 {
    32     CFather* cf = new CSon;
    33     cf -> AA();
    34     cf -> BB();
    35 
    36     CFather* cf1 = new CFather;
    37     cf1 -> AA();
    38     cf1 -> BB();
    39 
    40     CSon* cs = new CSon;
    41     cs -> AA();
    42     cs -> BB();
    43 
    44     return 0;
    45 }

    5.调用函数的区别:

    ①调用普通函数 调用哪一个函数 跟指针类型有关

    ②调用虚函数 看当前使用的虚函数列表是哪一个类的

    ③有作用域的话代表已经确定了 作用域的优先级别是最高的

    6.纯虚函数:

    ①格式:virtual void 函数名() = 0;

    ②注意:

    如果一个类包含纯虚函数 那这个类叫抽象类 抽象类是不可以定义对象的

    在派生类中一定要实现纯虚函数 那么这个派生类 也叫具体类

    如果一个类中的所有函数都是纯虚函数 那么这个类叫接口类

     1 #include<iostream>
     2 using namespace std;
     3 
     4 class CPerson
     5 {
     6 public:
     7     virtual void Eat() = 0;
     8 };
     9 
    10 class CChina : public CPerson
    11 {
    12     virtual void Eat()
    13     {
    14         cout << "CChina::Eat()" << endl;
    15     }
    16 };
    17 
    18 int main()
    19 {
    20     CPerson* cp = new CChina;
    21     cp -> Eat();
    22 
    23     return 0;
    24 }
  • 相关阅读:
    leetcode每日一题(2020-06-24):16. 最接近的三数之和
    leetcode每日一题(2020-06-23):67. 二进制求和
    leetcode每日一题(2020-06-19):125. 验证回文串
    leetcode每日一题(2020-06-18):1028. 从先序遍历还原二叉树
    leetcode每日一题(2020-06-17):1014. 最佳观光组合
    leetcode每日一题(2020-06-16):297. 二叉树的序列化与反序列化
    leetcode每日一题(2020-06-14):1300. 转变数组后最接近目标值的数组和
    leetcode每日一题(2020-06-13):70.爬楼梯
    leetcode每日一题(2020-06-12):15. 三数之和
    springboot 项目中_ 利用Filter去解决跨域问题
  • 原文地址:https://www.cnblogs.com/Aaaaaalei0612/p/9195188.html
Copyright © 2011-2022 走看看