栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++中的继承问题

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++中的继承问题

一、定义

C++ 中的继承是类与类之间的关系,是一个很简单很直观的概念,与现实世界中的继承类似,例如儿子继承父亲的财产。
继承(Inheritance)可以理解为一个类从另一个类获取成员变量和成员函数的过程。例如类 B 继承于类 A,那么 B 就拥有 A 的成员变量和成员函数。
        在C++中,派生(Derive)和继承是一个概念,只是站的角度不同。继承是儿子接收父亲的产业,派生是父亲把产业传承给儿子。
       被继承的类称为父类或基类,继承的类称为子类或派生类。“子类”和“父类”通常放在一起称呼,“基类”和“派生类”通常放在一起称呼。
        派生类除了拥有基类的成员,还可以定义自己的新成员,以增强类的功能。

继承的一般语法为:

class 派生类名:[继承方式] 基类名{
    派生类新增加的成员
};

例: 

#include
using namespace std;
//基类 Pelple
class People{
public:
    void setname(char *name);
    void setage(int age);
    char *getname();
    int getage();
private:
    char *m_name;
    int m_age;
};
void People::setname(char *name){ m_name = name; }
void People::setage(int age){ m_age = age; }
char* People::getname(){ return m_name; }
int People::getage(){ return m_age;}
//派生类 Student
class Student: public People{
public:
    void setscore(float score);
    float getscore();
private:
    float m_score;
};
void Student::setscore(float score){ m_score = score; }
float Student::getscore(){ return m_score; }
int main(){
    Student stu;
    stu.setname("小明");
    stu.setage(16);
    stu.setscore(95.5f);
    cout< 
二、三种继承方式 
  • 公共继承
  • 保护继承
  • 私有继承

  •  基类成员在派生类中的访问权限不得高于继承方式中指定的权限。
  • 不管继承方式如何,基类中的 private 成员在派生类中始终不能使用(不能在派生类的成员函数中访问或调用)。
  • 如果希望基类的成员能够被派生类继承并且毫无障碍地使用,那么这些成员只能声明为 public 或 protected;只有那些不希望在派生类中使用的成员才声明为 private。
  • 如果希望基类的成员既不向外暴露(不能通过对象访问),还能在派生类中使用,那么只能声明为 protected。
  • 注意,我们这里说的是基类的 private 成员不能在派生类中使用,并没有说基类的 private 成员不能被继承。实际上,基类的 private 成员是能够被继承的,并且(成员变量)会占用派生类对象的内存,它只是在派生类中不可见,导致无法使用罢了。private 成员的这种特性,能够很好的对派生类隐藏基类的实现,以体现面向对象的封装性。
  • 由于 private 和 protected 继承方式会改变基类成员在派生类中的访问权限,导致继承关系复杂,所以实际开发中我们一般使用 public。
class Base1 {
    public: 
            int m_A; 
    protected:
            int m_B; 
    private:
            int m_C; 
};

//公共继承 
class Son1 :public Base1 {
    public: 
        void func() { 
            m_A; //可访问 public权限
             m_B; //可访问 protected权限 
             //m_C; //不可访问
} 
};
void myClass()
 { 
     Son1 s1; 
     s1.m_A; //其他类只能访问到公共权限
 }
 
 //保护继承
  class Base2 {
      public: 
          int m_A;
      protected:
          int m_B; 
      private:
          int m_C; 
};

class Son2:protected Base2 {
    public: 
        void func() { 
            m_A; //可访问 protected权限
             m_B; //可访问 protected权限 
             //m_C; //不可访问 
} 
};
 
 void myClass2() { 
     Son2 s; 
     //s.m_A; //不可访问
      }
 
 //私有继承 
 class Base3 {
     public: 
         int m_A;
     protected:
         int m_B;
     private:
         int m_C; 
         };
 class Son3:private Base3 {
     public: 
         void func() { 
             m_A; //可访问 private权限
              m_B; //可访问 private权限 
              //m_C; //不可访问 
} 
};
class GrandSon3 :public Son3 {
    public: 
        void func() {
             //Son3是私有继承,所以继承Son3的属性在GrandSon3中都无法访问到 
             //m_A; 
             //m_B;
              //m_C; 
}
};

注意:在使用类创造的对象以及派生类的派生类时,注意访问权限的问题,只有public的继承方式才能访问,(小权限服从大权限)。

三、继承中的对象模型 问题:从父类继承过来的成员,哪些属于子类对象中?

一个派生类继承了所有的基类方法,但下列情况除外:

  • 基类的构造函数、析构函数和拷贝构造函数。
  • 基类的重载运算符。
  • 基类的友元函数。
  • 注意:私有成员只是被隐蔽了,但是会被继承下去
class Base {
    public: 
        int m_A; 
    protected:
        int m_B; 
    private:
        int m_C; //私有成员只是被隐藏了,但是还是会继承下去 
};
//公共继承
 class Son :public Base {
     public: 
         int m_D; 
};

     void test01() { 
         cout << "sizeof Son = " << sizeof(Son) << endl;
    }
    
int main() {
        test01(); 
        return 0;
    }
四、继承中的构造与析构顺序 子类继承父类后,当创建子类对象,也会调用父类的构造函数 问题:父类和子类的构造和析构顺序是谁先谁后?
class Base {
    public:
         Base() { 
             cout << "Base构造函数!" << endl; 
}
             ~Base() { 
                 cout << "Base析构函数!" << endl; 
}
};


class Son : public Base {
    public: 
        Son() {
             cout << "Son构造函数!" << endl; 
             }
             ~Son() { 
                 cout << "Son析构函数!" << endl;
} 
};

void test01() {
     //继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反 
     Son s;
}

int main() {
     test01(); 
     return 0; 
}

总结:在继承类中,先调用父类构造函数,在调用子类构造函数;析构函数与之相反。

五、继承同名成员处理方式 问题:当子类与父类出现同名的成员,如何通过子类对象,访问到子类或父类中同名的数据呢?
  • 访问子类同名成员 直接访问即可
  • 访问父类同名成员 需要加作用域
class Base { 
    public: 
        Base() { 
            m_A = 100; 
            }
        void func() {
                 cout << "Base - func()调用" << endl;
                  }
        void func(int a) {
                cout << "Base - func(int a)调用" << endl;
                         }
public: 
    int m_A;
};

class Son : public Base {
     public:
          Son() { m_A = 200;
          }
          //当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数
           //如果想访问父类中被隐藏的同名成员函数,需要加父类的作用域 
           void func()
            { 
                cout << "Son - func()调用" << endl; 
                } 
                public: 
                    int m_A; 
                };
void test01() {
     Son s; 
     cout << "Son下的m_A = " << s.m_A << endl;
     cout << "Base下的m_A = " << s.Base::m_A << endl; 
     s.func();
     s.Base::func();
     s.Base::func(10); 
}

int main() { 
    test01(); 
     return EXIT_SUCCESS; 
     }
总结: 1. 子类对象可以直接访问到子类中同名成员 2. 子类对象加作用域可以访问到父类同名成员 3. 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数 六、多继承 语法: class 子类 :继承方式 父类1 , 继承方式 父类2...
  • 多继承可能会引发父类中有同名成员出现,需要加作用域区分
  • C++实际开发中不建议用多继承
class Base1 {
     public: 
         Base1() { m_A = 100; }
     public: 
              int m_A; 
};
class Base2 {
     public:
          Base2() { m_A = 200; //开始是m_B 不会出问题,但是改为mA就会出现不明确 
          } 
          public: 
              int m_A; 
          };

//语法:class 子类:继承方式 父类1 ,继承方式 父类2
 class Son : public Base2, public Base1 {
     
     public: Son() { 
         m_C = 300; 
         m_D = 400;
} 
          public: 
              int m_C;
               int m_D;
};

      //多继承容易产生成员同名的情况 
      //通过使用类名作用域可以区分调用哪一个基类的成员

void test01() { 
    Son s; 
    cout << "sizeof Son = " << sizeof(s) << endl;
    cout << s.Base1::m_A << endl;
    cout << s.Base2::m_A << endl;
}

int main() { 
    test01();
     return 0; 
}
七、菱形继承 两个派生类继承同一个基类 又有某个类同时继承者两个派生类,这种继承被称为菱形继承,或者钻石继承。
  • 菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义
  • 利用虚继承可以解决菱形继承问题
class Animal {
public: 
int m_Age;
 };
//继承前加virtual关键字后,变为虚继承
//此时公共的父类Animal称为虚基类

class Sheep : virtual public Animal {}; 
class Tuo : virtual public Animal {};
class SheepTuo : public Sheep, public Tuo {};

void test01() {
 SheepTuo st;
 st.Sheep::m_Age = 100; 
 st.Tuo::m_Age = 200;
 cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;
 cout << "st.Tuo::m_Age = " << st.Tuo::m_Age << endl; 
 cout << "st.m_Age = " << st.m_Age << endl; 
}

int main() { 
test01(); 
system("pause");
return 0;
 }
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/869704.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号