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

 

posted @ 2018-06-18 14:44  Aaaaaalei  阅读(491)  评论(0编辑  收藏  举报