多态中的虚函数

  • 向上类型转换
 1 enum note {middleC,Csharp,Cflat};
 2 class Instrument {
 3 public:
 4     void  play(note) const {
 5         cout << "Instrument::play" << endl;
 6     }
 7 };
 8 
 9 class Wind: public Instrument {
10 public:
11     void  play(note) const {
12         cout << "Wind::play" << endl;
13     }
14 };
15 
16 void ture(Instrument& i) {
17 
18     i.play(middleC);
19 }
20 int main()
21 {
22     Wind flute;
23     tune(flute);
24 //最终打印结果为Instrument::play,向上类型转换虽然对象属于Wind,
25 //但是Wind继承于Instrument,这样ture(Instrument& i)即使传入的是Wind类,也能向上转换为Instrument类的对象
26 
27 }

变为虚函数后的结果就不同了

 1 enum note {middleC,Csharp,Cflat};
 2 class Instrument {
 3 public:
 4     void  play(note) const {
 5         cout << "Instrument::play" << endl;
 6     }
 7 };
 8 
 9 class Wind: public Instrument {
10 public:
11     virtual void  play(note) const {
12         cout << "Wind::play" << endl;
13     }
14 };
15 
16 void ture(Instrument& i) {
17 
18     i.play(middleC);
19 }
20 int main()
21 {
22     Wind flute;
23     tune(flute);//最终打印结果为Wind::play ,加上virtual关键字后,就可以保证继承的可扩展性,保证派生类自已拥有不同于基类的功能,实现函数的重新定义。
24 }
  • 抽象基类和纯虚函数

  在类的设计中,通常将基类作为派生类的一个标准接口,一般不创建基类的对象,建立基础的模板,它的派生类去重新定义函数的功能。纯虚函数禁止对抽象类的函数以传值方式调用,会发生对象切片,通过引用或指针可以避免。

 1 enum note {middleC,Csharp,Cflat};
 2 class Instrument {
 3 public:
 4     virtual void  play(note) const = 0;
 5     virtual char*  what() const = 0;
 6     virtual void  adjust(int) = 0;
 7 };
 8 
 9 class Wind: public Instrument {
10 public:
11     void  play(note) const
12     {
13         cout << "Wind::play" << endl;
14     }
15     char*  what() const
16     {
17         return "Wind";
18 
19     }
20     void  adjust(int) {}
21 };
22 class Percussion : public Instrument {
23 public:
24     void  play(note) const
25     {
26         cout << "Percussion::play" << endl;
27     }
28     char*  what() const
29     {
30         return "Percussion";
31 
32     }
33     void  adjust(int) {}
34 };
35 class Stringed : public Instrument {
36 public:
37     void  play(note) const
38     {
39         cout << "Stringed ::play" << endl;
40     }
41     char*  what() const
42     {
43         return "Stringed";
44 
45     }
46     void  adjust(int) {}
47 };
48 class Brass : public Wind {
49 public:
50     void  play(note) const
51     {
52         cout << "Brass ::play" << endl;
53     }
54     char*  what() const
55     {
56         return "Brass";
57 
58     }
59 };
60 class Woodwind : public Wind {
61 public:
62     void  play(note) const
63     {
64         cout << "Woodwind ::play" << endl;
65     }
66     char*  what() const
67     {
68         return "Woodwind";
69 
70     }
71 };
72 void ture(Instrument& i) {
73 
74     i.play(middleC);
75 }
76 void f(Instrument& i)
77 {
78     i.adjust(1);
79 }
80 int main()
81 {
82     Wind flute;
83     Percussion drum;
84     Stringed violin;
85     Brass fluge;
86     Woodwind recorder;
87     tune(flute);
88     tune(drum);
89     tune(violin);
90     tune(fluge);
91     tune(recorder);
92     f(fluge);
93 }
  • 对象切片

  解决多态中,基类对象操作派生类对象的问题,对象切片会使基类访问不到派生类,不能使多态有意义。

 1 class Pet {
 2     string pname;
 3 public:
 4     Pet(const string& name) :pname(name) {}
 5     virtual string name() const { return pname; }
 6     virtual string description()const
 7     {
 8         return pname;
 9     }
10 };
11 
12 class Dog : public Pet {
13     string factive;
14 public:
15     Dog(const string& name, const string& active) :Pet(name), factive(active) {}
16     string description() {
17         return factive;
18     }
19 };
20 void  description(Pet p) //传入的使值,不是引用不是指针地址
21 {
22     cout << p.description() << endl;
23 }
24 
25 int main()
26 {
27     Pet p("Alfred");
28     Dog d("Fluffy","sleep");
29     description(p);
30     description(d);
31 //我们希望description(p)出现Alfred结果,description(d)出现sleep结果,
32 //但是实际最终的结果是description(d)出现Fluffy,调用的同样是基类的函数,
33 //而不是派生类的。因为传值的过程不能改变地址。
34 }
  • 重载和重新定义

  重新定义一个基类的重载函数时,将会隐藏所有该重载函数的其他基类函数,但是当对虚函数进行操作重新定义时会不太一样。下面的d4和引用是其中的区别.

 1 class Base {
 2 public:
 3     virtual int f()const {
 4         cout << "Base::f()";
 5         return 1;
 6     }
 7     virtual void f(string) const {}
 8     virtual void g() const {}
 9 };
10 
11 class Derived1 :public Base {
12 public:
13     void g() cont {}
14 };
15 class Derived2 :public Base {
16 public:
17     int f() cont {
18         cout << "Derived2::f()";
19         return 2;
20     }
21 };
22 class Derived3 :public Base {
23 public:
24     /*void f() const {
25         cout << "Derived3::f()";
26         return 3;
27     }*///非法,不能改变返回类型
28 };
29 class Derived4 :public Base {
30 public:
31     int f(int) cont {
32         cout << "Derived4::f()";
33         return 3;
34     }
35 };
36 int main()
37 {
38     srting s("hello");
39     Derived1 d1;
40     int x = d1.f();
41     d1.f(s);
42     Derived2 d2;
43     x = d2.f();
44     //d2.f(s);隐藏
45     Derived4 d4;
46     x = d4.f(1);
47     //x=d4.f();隐藏
48     //d4.f(s);隐藏
49     Base& br = d4;
50     //br.f(1);
51     br.f();
52     br.f(s);//与Derived4 d4相反
53 }
posted @ 2020-01-05 22:38  静精进境  阅读(217)  评论(0编辑  收藏  举报