zoukankan      html  css  js  c++  java
  • 35 同名覆盖引发的问题

    1 父子间的赋值兼容

    • 子类对象可以当作父类对象使用(兼容性)

      • 子类对象可以直接赋值给父类对象
      • 子类对象可以直接初始化父类对象
      • 父类指针可以直接指向子类对象:多态
      • 父类引用可以直接引用子类对象
    • 示例:子类对象的兼容性

      • Demo

        #include <iostream>
        #include <string>
        
        using namespace std;
        
        class Parent
        {
        public:
            int mi;
            
            void add(int i)
            {
                mi += i;
            }
            
            void add(int a, int b)
            {
                mi += (a + b);
            }
        };
        
        class Child : public Parent
        {
        public:
            int mv;
            
            void add(int x, int y, int z)
            {
                mv += (x + y + z);
            }
        };
        
        int main()
        {
            Parent p;
            Child c;
            
            p = c;
            
            Parent p1(c);
            
            
            Parent& rp = c;  //父类引用:引用子类对象
            Parent* pp = &c;  //父类指针:指向子类对象
            
            rp.mi = 100;
            rp.add(5);             // 没有发生同名覆盖
            rp.add(10, 10);        // 没有发生同名覆盖
            
            //编译错误
            pp->mv = 1000;
            pp->add(1, 10, 100);
            
            return 0;
        }
        
      • 编译

        test.cpp: In fuction 'int main()':
        test.cpp:51: error: 'class Parent' has no member named 'mv'
        test.cpp:52: error: no matching function for call to 'Parent::add(int,int,int)'
        test.cpp:11:note: candidates are: void Parent::add(int)
        test.cpp:16:note:                 void Parent::add(int,int)
        
    • 当使用父类指针(引用)指向子类对象时

      • 子类对象退化为父类对象
      • 只能访问父类中定义的成员
      • 可以直接访问被子类覆盖的同名成员,如父类的 add(int)add(int,int) 被子类的 add(int,int,int) 所覆盖

    2 特殊的同名函数

    • 子类中可以重定义父类中已经存在的成员函数:重定义的原因是父类中的函数不能满足使用

    • 这种定义发生在继承中,叫做函数重写

    • 函数重写是同名覆盖的一种特殊情况

      class Parent
      {
      public:
          void print()
          {
              cout << "I'm Parent." << endl;
          }
      };
      
      //函数重写
      class Child : public Parent
      {
      public:
          //函数原型与父类中的完全相同,此处函数重写是必须的
          void print()
          {
              cout << "I'm Child." << endl;
          }
      };
      
    • 问题:当函数重写遇到赋值兼容会发生什么?

    • 示例:函数重写 VS 赋值兼容

      • Demo

        #include <iostream>
        #include <string>
        
        using namespace std;
        
        class Parent
        {
        public:
            int mi;
            
            void add(int i)
            {
                mi += i;
            }
            
            void add(int a, int b)
            {
                mi += (a + b);
            }
            
            //打印父类信息
            void print()
            {
                cout << "I'm Parent." << endl;
            }
        };
        
        class Child : public Parent
        {
        public:
            int mv;
            
            void add(int x, int y, int z)
            {
                mv += (x + y + z);
            }
            
            //重写函数:打印子类信息
            void print()
            {
                cout << "I'm Child." << endl;
            }
        };
        
        void how_to_print(Parent* p)
        {
            p->print();
        }
        
        int main()
        {
            Parent p;
            Child c;
            
            p.print();
            c.print();
            
            how_to_print(&p);    // Expected to print: I'm Parent.
            how_to_print(&c);    // Expected to print: I'm Child.
            
            return 0;
        }
        
      • 编译运行

        I'm Parent.
        I'm Child.
        
        I'm Parent.
        I'm Parent.  !!!!!!
        
    • 问题分析

      • 编译期间,编译器只能根据指针的类型判断所指向的对象

      • 根据赋值兼容,编译器认为父类指针指向的是父类对象

      • 因此,编译结果只可能是调用父类中定义的同名函数

      • 在编译下面的函数时,编译器不可能知道指针 p 究竟指向了什么,但是编译器没有理由报错。于是编译器认为最安全的做法是调用父类的 print 函数,因为父类和子类肯定都有相同的 print 函数。但不是期望的! => 使用多态解决

        void how_to_print(Parent* p)
        {
            p->print();
        }
        
  • 相关阅读:
    移动端轮播插件
    一个简单的富文本编辑器
    animation css3
    渐变的写法
    js拖拽功能
    打子弹游戏 js
    css-vertical-centering
    css3的linear-gradient
    js模拟滚动条
    js日历
  • 原文地址:https://www.cnblogs.com/bky-hbq/p/13903910.html
Copyright © 2011-2022 走看看