鱼C论坛

 找回密码
 立即注册
查看: 1237|回复: 5

[已解决]类的继承

[复制链接]
发表于 2018-12-20 15:03:05 | 显示全部楼层 |阅读模式
50鱼币
#include <iostream>
#include <string>

class Father_class
{
public:
        Father_class(std::string name1);
        ~Father_class();
        void show_name();
       
protected:
        std::string name;
};

class Son_class : public Father_class
{
public:
        Son_class(std::string name1);
        ~Son_class();


};

Father_class :: Father_class(std::string name1)
{
        name = name1;
        std::cout << "now in Father 构造器" <<std::endl;
}

Father_class :: ~Father_class()
{
        std::cout << "now in Father 析构器" << std::endl;
}

void Father_class :: show_name()
{
        std::cout << "name is " << name << std::endl;
}

Son_class :: Son_class(std::string name1) : Father_class("aaa")
{
        std::cout << "Now in Son_class的构造器中 " << std::endl;
        name = name1;
        std::cout << "now name of Son_class is : " << name << std::endl;
        std::cout << "now name of Father_class is : " ;
        Father_class ::show_name()  ;
        std::cout << "$$$$$$$$$$$$$" << std::endl;
       
}

Son_class :: ~Son_class()
{
        std::cout << "now in Son_class的析构器中" <<std::endl;
}

int main()
{
        Son_class tom("tom");
        tom.show_name();
        return 0;
}

结果如图1

然后将父类中的name 的属性改为private
子类中定义自己的private : std::string name ;

结果如图二。
求问为什么tom.get_name()的结果会有不同?
在结果图1,图2中第四行的father_name 的name 也不同。
内部运行的流程是如何的?


最佳答案
2018-12-20 15:03:06
本帖最后由 sunrise085 于 2018-12-20 16:51 编辑

关于类的继承,一定要记住这三种属性的作用范围。public属性的作用域最广,可继承,可访问;protected属性的作用域稍弱,可继承,不可访问;private属性的作用域最小,不可继承,不可访问。以上所说的作用域范围都是在类以外,对于类的成员函数访问类的成员变量或成员函数不受属性范围限制。
下面以你的这个程序为例向你详细解释一下。
在现有的程序中,子类Son继承于父类Father,因父类中的成员变量name属性是protected,因此能够被继承,而且子类Son中没有同名的成员变量,因此成员变量name完全继承于父类Father,在创建子类Son的对象的时候和Father共用一个成员变量name;还有就是Father类的成员函数show,也被继承下来。
先说图一的执行过程:
在执行Son_class tom("tom")的时候,调用Son构造函数,因Son类是继承于Father类,所以在执行Son构造函数之前先执行Father的构造函数,进入Father的构造函数:
在Father的构造函数中,执行第一句后name="aaa",然后执行第二句,输出"now in Father 构造器";
此时tom.name="aaa",但是构造函数还没执行完,接着返回到Son构造函数:
在Son的构造函数中,执行第一句后,输出"Now in Son_class的构造器中",执行第二句,name被修改为"tom",在执行下面的语句时,Son类的对象tom的成员变量name已经是"tom",因此输出Father的name和Son的name都是tom,输出"$$$$$$$$$$$$$"之后,Son构造函数彻底执行完成;
接下来执行第二句, tom.show_name(),调用了从父类Father类中继承来的成员函数show(),输出了"name is tom";
最后程序结束,销毁在main()中创建的Son类对象tom,因此执行Son的析构函数,执行析构函数的顺序与构造函数的顺序相反,先析构子类,再析构父类。

在此程序中,子类Son的构造函数继承时,Father类后面的"aaa"没有任何作用,因为一进入构造函数,就被name1修改了,但是这里又必须要写,因为Father类的构造函数是需要参数了,所以必须写一个参数。

再说一说修改之后的程序。修改之后,Father中的成员变量name属性变为private,无法被继承,而且在子类Son中有一个同名的成员变量,它与Father的name相当于是两个独立的变量(这里为了区别,暂时称之为name_f和name
_s);子类Son中没有成员函数show(),而父类Father类的show()是可以继承的,因此子类Son继承了父类Father的成员函数,但是因为它是父类的成员函数,因此所访问的name是name_f,而不是name_s。
下面我们看一下按程序的执行过程:
在执行Son_class tom("tom")的时候,调用Son构造函数,因Son类是继承于Father类,所以在执行Son构造函数之前先执行Father的构造函数,进入Father的构造函数:
在Father的构造函数中,执行第一句后name_f被赋值"aaa",然后执行第二句,输出"now in Father 构造器";
此时name_f="aaa",但是构造函数还没执行完,接着返回到Son构造函数:
在Son的构造函数中,执行第一句后,输出"Now in Son_class的构造器中",执行第二句,name_s被赋值为"tom",Son类的对象tom的成员变量name已经是"tom",而此时Father的name仍然是"aaa",和Son的name是不一样的,
在执行构造函数第三行时,因为是在Son的构造函数中,因此语句中的name指的是name_s,即"tom",输出"now name of Son_class is : tom",
在执行第四行时,调用成员函数show(),而该函数来自父类,访问的是name_f,因此输出"now name of Father_class is : name is aaa",输出"$$$$$$$$$$$$$"之后,Son构造函数彻底执行完成;
接下来执行第二句, tom.show_name(),调用了从父类Father类中继承来的成员函数show(),因此输出的仍然是Father的成员变量name,输出了"name is aaa";
最后程序结束,销毁在main()中创建的Son类对象tom,因此执行Son的析构函数,执行析构函数的顺序与构造函数的顺序相反,先析构子类,再析构父类。

在修改之后的程序中,因为子类中没有重载父类的show(),因此一直使用的都是父类的函数,不管在调用之前是否添加Father_class::,所以在Son的构造函数中,第五行Father_class ::show_name() ,可以省略前面的Father_class::,效果是一样的。

此外你可以尝试一下,在子类中重载show()函数,然后看看运行结果,调用show()函数时前面是否添加Father_class,结果就不一样了。
图2.png
图1.png

最佳答案

查看完整内容

关于类的继承,一定要记住这三种属性的作用范围。public属性的作用域最广,可继承,可访问;protected属性的作用域稍弱,可继承,不可访问;private属性的作用域最小,不可继承,不可访问。以上所说的作用域范围都是在类以外,对于类的成员函数访问类的成员变量或成员函数不受属性范围限制。 下面以你的这个程序为例向你详细解释一下。 在现有的程序中,子类Son继承于父类Father,因父类中的成员变量name属性是protected,因此能 ...
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-12-20 15:03:06 | 显示全部楼层    本楼为最佳答案   
本帖最后由 sunrise085 于 2018-12-20 16:51 编辑

关于类的继承,一定要记住这三种属性的作用范围。public属性的作用域最广,可继承,可访问;protected属性的作用域稍弱,可继承,不可访问;private属性的作用域最小,不可继承,不可访问。以上所说的作用域范围都是在类以外,对于类的成员函数访问类的成员变量或成员函数不受属性范围限制。
下面以你的这个程序为例向你详细解释一下。
在现有的程序中,子类Son继承于父类Father,因父类中的成员变量name属性是protected,因此能够被继承,而且子类Son中没有同名的成员变量,因此成员变量name完全继承于父类Father,在创建子类Son的对象的时候和Father共用一个成员变量name;还有就是Father类的成员函数show,也被继承下来。
先说图一的执行过程:
在执行Son_class tom("tom")的时候,调用Son构造函数,因Son类是继承于Father类,所以在执行Son构造函数之前先执行Father的构造函数,进入Father的构造函数:
在Father的构造函数中,执行第一句后name="aaa",然后执行第二句,输出"now in Father 构造器";
此时tom.name="aaa",但是构造函数还没执行完,接着返回到Son构造函数:
在Son的构造函数中,执行第一句后,输出"Now in Son_class的构造器中",执行第二句,name被修改为"tom",在执行下面的语句时,Son类的对象tom的成员变量name已经是"tom",因此输出Father的name和Son的name都是tom,输出"$$$$$$$$$$$$$"之后,Son构造函数彻底执行完成;
接下来执行第二句, tom.show_name(),调用了从父类Father类中继承来的成员函数show(),输出了"name is tom";
最后程序结束,销毁在main()中创建的Son类对象tom,因此执行Son的析构函数,执行析构函数的顺序与构造函数的顺序相反,先析构子类,再析构父类。

在此程序中,子类Son的构造函数继承时,Father类后面的"aaa"没有任何作用,因为一进入构造函数,就被name1修改了,但是这里又必须要写,因为Father类的构造函数是需要参数了,所以必须写一个参数。

再说一说修改之后的程序。修改之后,Father中的成员变量name属性变为private,无法被继承,而且在子类Son中有一个同名的成员变量,它与Father的name相当于是两个独立的变量(这里为了区别,暂时称之为name_f和name
_s);子类Son中没有成员函数show(),而父类Father类的show()是可以继承的,因此子类Son继承了父类Father的成员函数,但是因为它是父类的成员函数,因此所访问的name是name_f,而不是name_s。
下面我们看一下按程序的执行过程:
在执行Son_class tom("tom")的时候,调用Son构造函数,因Son类是继承于Father类,所以在执行Son构造函数之前先执行Father的构造函数,进入Father的构造函数:
在Father的构造函数中,执行第一句后name_f被赋值"aaa",然后执行第二句,输出"now in Father 构造器";
此时name_f="aaa",但是构造函数还没执行完,接着返回到Son构造函数:
在Son的构造函数中,执行第一句后,输出"Now in Son_class的构造器中",执行第二句,name_s被赋值为"tom",Son类的对象tom的成员变量name已经是"tom",而此时Father的name仍然是"aaa",和Son的name是不一样的,
在执行构造函数第三行时,因为是在Son的构造函数中,因此语句中的name指的是name_s,即"tom",输出"now name of Son_class is : tom",
在执行第四行时,调用成员函数show(),而该函数来自父类,访问的是name_f,因此输出"now name of Father_class is : name is aaa",输出"$$$$$$$$$$$$$"之后,Son构造函数彻底执行完成;
接下来执行第二句, tom.show_name(),调用了从父类Father类中继承来的成员函数show(),因此输出的仍然是Father的成员变量name,输出了"name is aaa";
最后程序结束,销毁在main()中创建的Son类对象tom,因此执行Son的析构函数,执行析构函数的顺序与构造函数的顺序相反,先析构子类,再析构父类。

在修改之后的程序中,因为子类中没有重载父类的show(),因此一直使用的都是父类的函数,不管在调用之前是否添加Father_class::,所以在Son的构造函数中,第五行Father_class ::show_name() ,可以省略前面的Father_class::,效果是一样的。

此外你可以尝试一下,在子类中重载show()函数,然后看看运行结果,调用show()函数时前面是否添加Father_class,结果就不一样了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-12-20 19:41:58 | 显示全部楼层
sunrise085 发表于 2018-12-20 16:47
关于类的继承,一定要记住这三种属性的作用范围。public属性的作用域最广,可继承,可访问;protected属性 ...

十分感谢您的回复
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-12-20 19:47:24 | 显示全部楼层
sunrise085 发表于 2018-12-20 15:03
关于类的继承,一定要记住这三种属性的作用范围。public属性的作用域最广,可继承,可访问;protected属性 ...

这里还有一个小问题,我在Son_class中也定义一个protected :的 std::string name,  那么两个name也不会相互覆盖或者相互影响是吗? why?(通过尝试 结果上是没有影响)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-12-20 20:05:30 | 显示全部楼层
竟无语凝噎 发表于 2018-12-20 19:47
这里还有一个小问题,我在Son_class中也定义一个protected :的 std::string name,  那么两个name也不会 ...

不会相互影响的。在子类中有和父类中相同名字的成员函数叫函数重载,若有和父类中名称相同的成员变量,也可以称之为重载,相互之间不影响,都会存在,只是父类的c成员函数调用的就是父类的成员变量,子类的成员函数调用的就是子类的成员变量,在子类中调用父类的成员变量则需要在前面加上Father_class::

评分

参与人数 1荣誉 +5 鱼币 +5 贡献 +3 收起 理由
竟无语凝噎 + 5 + 5 + 3

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-12-21 09:35:44 | 显示全部楼层
sunrise085 发表于 2018-12-20 20:05
不会相互影响的。在子类中有和父类中相同名字的成员函数叫函数重载,若有和父类中名称相同的成员变量,也 ...

十分感谢您的解答
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-1 00:35

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表