码迷,mamicode.com
首页 > 其他好文 > 详细

同名覆盖引发的问题(四十一)

时间:2018-05-28 17:25:17      阅读:120      评论:0      收藏:0      [点我收藏+]

标签:C++   同名覆盖   赋值兼容   函数重写   

        在子类继承父类后,子类对象便可以当做父类对象使用了(兼容性)。包括:1、子类对象可以直接赋值给父类对象;2、子类对象可以直接初始化父类对象;3、父类对象可以直接指向子类对象;4、父类引用可以直接引用子类对象。那么我们来编程看看子类对象的兼容性

#include <iostream>
#include <string>

using namespace std;

class Parent
{
public:
    int mi;
    
    void add(int v)
    {
        mi += v;
    }
    
    void add(int a, int b)
    {
        mi += (a + b);
    }
};

class Child : public Parent
{
public:
    int mv;
    
    void add(int a, int b, int c)
    {
        mv += (a + b + c);
    }
};

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

        我们先来看看第 38 行将子类对象 c 直接赋值给父类对象 p,这样编译会通过吗?还有第 40 行的初始化操作。再将子类对象 c 赋值给父类对象的引用 rp,将父类对象的指针 pp 指向对象 c 的地址。通过 rp 调用父类对象的成员变量和成员函数,看看会报错吗?照理说这块应该会发生同名覆盖,我们看看编译结果

技术分享图片

        编译是通过的,也就证明没有发生同名覆盖。那么我们再来将第 49 和 50 行的注释去掉,看看通过指针 pp 指向的子类对象 c 直接调用子类对象的成员变量和成员函数会通过吗?

技术分享图片

        我们看到编译出错了。下来我们来说下当使用父类指针(引用)指向子类对象时,子类对象便退化为父类对象,只能访问父类中定义的成员,可以直接访问被子类覆盖的同名成员。这也就不难解释上面没有发生同名覆盖以及通过指针来调用子类对象的成员变量和成员函数出错的情况了。

        在子类中可以重定义父类中已经存在的成员函数,这种重定义发生在继承中,叫做函数重写函数重写是同名覆盖的一种特殊情况。当函数重写遇上赋值兼容会发生什么呢?我们通过是来代码来分析下

#include <iostream>
#include <string>

using namespace std;

class Parent
{
public:
    void print()
    {
        cout << "I'm Parent!" << endl;
    }
};

class Child : public Parent
{
public:
    void print()
    {
        cout << "I'm Child!" << endl;
    }
};

void how_to_print(Parent* p)
{
    p->print();
}

int main()
{
    Parent p;
    Child c;
    
    p.print();         // I'm Parent!
    c.print();         // I'm Child!
    
    cout << endl;
    
    how_to_print(&p);  // I'm Parent!
    how_to_print(&c);  // I'm Child!
    
    return 0;
}

        我们分别在父类和子类中定义 print 函数,打印相关信息。我们期望的是 p.print() 打印的是 I'm Parent!;c.print() 打印的是 I'm Child!;在调用全局函数 how_to_print() 时,如果传入的是父类指针,我们期望打印的是 I'm Parent!,如果传入的是子类指针,则打印的是 I'm Child!。下来我们来编译看看结果

技术分享图片

        我们直接调用的时候打印的是对的,但是在传入对象的时候,打印的是错的。我们传入的是子类对象,但是打印出来的是父类的函数,我们会不会很奇怪呢?在编译期间,编译器只能根据指针的类型判断所指向的对象,根据赋值兼容,编译器认为父类指针指向的是父类对象。因此,编译结果只可能是调用父类中定义的同名函数。那么在编译到 how_to_print(Parent* p) 这个函数时,编译器不可能知道指针 p 究竟指向了什么。但是编译器没有理由报错。于是乎,编译器认为最安全的做法是调用父类的 print 函数,因为父类和子类肯定都有相同的 print 函数。因此便出现了这个编译结果,那么编译器的处理方法是合理的吗?是期望的吗?显然从安全的角度来说,它的处理是合理的,但却不是我们所期望的。在后面我们会继续讲解这个问题的。

        通过对同名覆盖的学习,总结如下:1、子类对象可以当做父类对象使用(赋值兼容);2、父类指针可以正确的指针子类对象;3、父类引用可以正确的代表子类对象;4、子类中可以重写父类中的成员函数。


        欢迎大家一起来学习 C++ 语言,可以加我QQ:243343083

同名覆盖引发的问题(四十一)

标签:C++   同名覆盖   赋值兼容   函数重写   

原文地址:http://blog.51cto.com/12810168/2121148

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!