zoukankan      html  css  js  c++  java
  • 多态中的虚函数

    • 向上类型转换
     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 }
  • 相关阅读:
    数据库 | 建表常用语句
    心得 | 撰写项目申报书
    工具 | 时间转化
    SpringBoot | 启动异常 | 显示bulid success 无 error信息
    120. 三角形最小路径和
    63. 不同路径 II
    SpringBoot | Velocity template
    SpringBoot | quartz | @DisallowConcurrentExecution
    SpringBoot | Hibernate @Transient 注解
    Java | 基础归纳 | 静态方法与实例方法的区别
  • 原文地址:https://www.cnblogs.com/fuzhuoxin/p/12153971.html
Copyright © 2011-2022 走看看