• C++面向对象基础:访问权限、三种继承权限详解


    引言

    继承是面向对象中十分重要的一个概念,通过继承可以对很多有某种共性的事物进行抽象。许多课程中介绍继承,都会用父子关系来叙述几个类之间的关系,但这种描述并不能很好解释继承的真谛。基类的设计,应该是对具某类事物属性与方法的抽象;子类继承自基类,应当继承的是基类的基本功能,并且应该要有自己独特的属于与方法。两者直接是一种派生关系,在模仿的基础上有自己的特点,而不是单纯的属于关系。有一种动物叫做骡子,驴与马结合所生,骡子既不是马也不是驴,但它结合了两者的很多特点。

    继承权限与访问权限

    内部访问与外部访问

    内部访问:在类内部定义类函数等操作,访问类的属性或者方法叫做内部访问。
    外部访问:在类的外部,比如创建了一个类实例对象,通过点.操作符或者->操作符来访问类数据或方法,叫做外部访问。

    弄清这两个东西后,我们接着讲解两种权限。

    访问权限

    在C++中,继承权限与访问权限一样,都有三种:public、protected、private。
    在三种访问权限(不牵扯到继承与友元)中,声明为public的属性与方法,内部与外部均可访问到;proteced与private只能在其内部访问。按照保护程度来排序,应为:private>protected>public
    代码测试:
    基类的定义

    class Human{
    public:
        Human(){
            name = "无名";
            gender = "男";
            age = 0;
        }
        Human(const string&name,const string&gender,int age):name(name),gender(gender),age(age){}
        string name;
        int getAge(){return this->age;}
        string getGender(){return this->gender;}
    protected:
        string gender;
    private:
        int age;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    测试函数:

    void testHuman()
    {
        Human h1;
        //通过 . 运算符只能获取到name 但获取不到gender 
        //h1.gender ;报错 在类外部访问proteced成员 
        //h1.age;//报错 相当于在类外部访问private成员
        
        cout<<"h1的信息"<<h1.name<<" "<<h1.getAge()<<"岁 性别"<<h1.getGender()<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    由此可见,在单纯的访问时,上面三种权限的说明是正确的,只有public权限才能在类外部访问,其它两种均只能在类内部访问。

    继承权限

    不管是哪种继承权限,都可以说将父类中的属性与方法再改访问权限放入到子类中,有一点需要注意的是,protected权限,除了在基类内部访问以外,还能在其子类中访问。
    此处先分别通过三个测试案例来进行讲解。

    public继承

    子类定义:

    class Man:public Human{
        public:
            Man():Human(){}
            Man(const string&name,const string&gender,int age):Human(name,gender,age){}
            string getName(){return this->name;}
            // 在子类内部 可以访问基类的protected权限的属性与方法
            string getGender(){return this->gender;}
            // 报错 age不可访问 父类的private 是只能父类在类内部才能直接访问
            // 类外部 即便是子类也不能直接访问 但可通过父类的getAge来间接访问
            //int getAge(){return this->age;}
    };  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    测试代码:

    void testPublicInherit()
    {
        Man m1;
        //可以访问原来的public权限的属性与方法
        cout<<m1.name<<"\t"<<m1.getAge()<<endl;
        //尝试在类外部访问protected和private
        //m1.gender; 报错 . 不出来这个属性
        //m1.age; 报错 . 不出来这个属性
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    由此可见,public继承时,基类中的public与protected权限的属性、方法,在子类中权限并不会被改变,但对于基类private的,可以理解为它在哪定义为private的,就只有在哪个类内部才能直接访问。

    protected继承

    子类定义:

    class Woman:protected Human{
        public:
            Woman():Human(){}
            Woman(const string&name,const string&gender,int age):Human(name,gender,age){}
            //在子类中 基类protected权限的可以直接访问
            string getname(){return this->name;}
            string getgender(){return this->gender;}
            //报错 相当于在Human外部直接访问age 可以通过getAge函数间接访问
            //string getage(){return this->age;}
            int getage(){return Human().getAge();}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    测试代码:

    void testProtectedInherit()
    {
        Woman w1;
        //尝试访问原来public权限的属性与方法
        //cout<
        //cout<
        //可见 protected继承后 基类中public权限的属性与方法 不再是public
        //通过自己的函数 来间接访问
        //gender、name在子类定义的函数中可以直接访问 那么gender、name的权限为protected
        cout<<w1.getage()<<"\t"<<w1.getgender()<<"\t"<<w1.getname()<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    至于为什么gender、name在子类中的权限为protected,可以通过再次public继承Woman类来测试,子类定义:

    class Girl:public Woman{
        public:
            Girl():Woman(){}
            Girl(const string&name,const string&gender,int age):Woman(name,gender,age){}
            //测试是否能直接访问Woman类中的name和gender
            void test(){ cout<<this->name<<"\t"<<this->gender<<endl;}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试代码:

    	Girl g1;
        //测试是否能直接访问
        //cout<
        //在内部函数可以直接访问不报错 因此在基类Woman中 name gender必定不为private
        g1.test();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    private继承

    子类定义:

    class Hemophrodite:private Human{
        public:
            Hemophrodite():Human(){}
            Hemophrodite(const string&name,const string&gender,int age):Human(name,gender,age){}
            //内部能直接访问 基类访问权限为public与protected的属性方法
            string getgender(){return this->gender;}
            string getname(){return this->name;}
            //尝试能否直接访问 private
            //int getage(){return this->age;} 不可访问 
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    测试代码:

    void testPrivateInherit()
    {
        Hemophrodite hp;
        //尝试直接访问基类的属性
        //cout<
        //尝试访问基类的方法
        //cout<
        //尝试通过自身定义的函数来访问 不报错
        cout<<hp.getgender()<<hp.getname()<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    相信通过代码与注释,各位读者应该有了一些猜想,在此总结一下:
    在继承时,若继承权限的保护程度高于访问权限,那么继承权限会将访问权限覆盖,比如private继承时,基类中public与protected的权限,在子类中均为private访问权限;若低于或者相等,则不变。需要注意的是,继承并不是将属性与方法改一下权限然后全扔到子类里面,而是还加上了父类的访问权限,如父类的private属性方法,是只能在父类内部访问的,无论以何种继承,是无法在子类中直接访问的(但可间接访问)。
    最后举三个例子
    public继承:购物广场对于人们而言,是所有人都能进去玩耍的,大部分地方相当于public访问权限,但里面有些地方普通人进不去,只能工作人员进去,相当于protected访问权限,而有些地方只能商场老板使用,相当于private访问权限。
    protected继承:有些餐馆只对内部VIP开放,即相当于只能子类才能访问,但VIP也不能访问所有地方。
    private继承:房屋是私有财产,只有有限的几个家人才能访问,家人能使用客厅、卫生间,但一般不能访问家人的隐私。

  • 相关阅读:
    MATLAB被禁下一个会是LABVIEW吗?国产测试软件ATECLOUD崛起发力
    前端性能优化方法与实战02 性能瓶颈点:从 URL 输入到页面加载整过程分析
    9.2.5.2 【MySQL】XDES 类型
    Redis 主从复制
    Dart学习——函数、类
    idea联合es 做出jd爬虫
    PAT 1139 First Contact
    【C++11算法】is_sorted、is_sorted_until
    【GESP考级C++】1级样题 闰年统计
    数据结构和算法(二)--算法分析
  • 原文地址:https://blog.csdn.net/weixin_45416439/article/details/126212454