C++继承

继承

  • 继承是类中成员的复用。
  • 有元关系无法被继承。

继承的定义和使用方法

  • 下列父类成员 pri 为private,所以子类无法访问。其他成员子类皆可访问。
  • 下列子类以protected 方式继承父类,所以子类的对象对父类的访问权限最高为protected。
  • 父类中成员函数 Print() 为public,但是子类继承方式为 protected,所以子类对象对 Print()的访问权限为 protected,无法访问。
class Person    //父类
{
public:
    void Print()
    {
        cout << "name:" << _name << endl;
        cout << "age:" << _age << endl;
    }
protected:
    string _name = "bjf";
    int _age = 18;    
private:
    int pri = 5;
};

class Student :protected Person   //继承Person类,子类 
public:
    void test()
    {
        cout << _name << endl;
        cout << _age << endl;
        Print();
    }
private:
    int code;
};

int main()
{
    Student xiaoming;
    xiaoming.test();
    return 0;
}
  • 继承方式只决定子类的对象对父类成员的最高访问权限(最低权限取决于成员本身的权限),不影响子类对父类的访问权限。
  • 子类可以访问父类的所有成员,除了私有成员(只是不能访问私有成员,但是子类仍然继承了的)
  • class默认的继承方式是private,struct默认继承方式是pubilc。

类对象间的赋值规则

  • 可以将子类对象赋值给父类对象。(父类对象不能赋值子类对象)
int main()
{
    Student bjf;
    Person  man;
    man = bjf;  //用子类对象赋值父类的对象,只将子类中继承的父类成员赋值过去,而子类自己的成员不管
    Person* woman = &bjf;  //woman指针,只代表bjf中的父类成员。
    return 0;
}

继承中的作用域(关于隐藏)

  • 在继承的体系中,父类和子类有独立的作用域。
  • 如果父类和子类有同名成员,则需要表明该成员属于哪个类,否则会根据就近原则默认是子类的成员。(子类成员屏蔽了父类成员的直接访问,这就是隐藏)
  • 注意:如果是同名成员函数,这个也是隐藏,需要指明属于哪个类(这个不是函数重载)
class Person
{
public:
    int mun = 10;
};

class Student :public Person   //继承Person类 
{
public:
    void test()
    {
        cout << mun << endl;  //输出为 5,就近原则
        cout << Person::mun << endl;  //输出为 10    
    }
    int mun = 5;
};


int main()
{
    Student xiaoming;
    xiaoming.test();
    return 0;
}

父类成员变量的初始化

  • 子类对父类成员变量的初始化,必须调用父类的构造函数进行初始化。
  • 注意:

    • 子类对象初始化时,是先初始化父类成员,再初始化子类成员。
    • 在程序结束自动调用析构函数时,理论上是先调用子类的析构函数然后调用父类的析构函数(栈先进后出),但是编译器在这个前默认调用类一次父类的析构函数
    • 所以,实际的析构顺序是 父类析构—子类析构—父类析构(父类析构被调用两次)
  • 注意:父类的析构函数和子类的析构函数,他们函数名不同,但是仍然会触发隐藏

    • 因为在编译器中,任何类的析构函数都会被统一处理成 destructor()。
class Person
{
public:
    Person(int b)
        :_mun(b)
    {}
protected:
    int _mun;
};

class Student :public Person   //继承Person类 (student是子类,Person是父类)
{
public:
    Student(int a, int b)
        :_mun(a)
        , Person(b)  //调用父类的构造函数
    {
    }
    void test()
    {
        cout << _mun << endl;  //输出为 7,就近原则
        cout << Person::_mun << endl;  //输出为 8    
    }
protected:
    int _mun;
};
int main()
{

    Student xiaoming(7, 8);
    xiaoming.test();
    return 0;
}

多继承

  • 多继承:一个子类有多个直接父类。

菱形继承

C++继承_第1张图片

  • 菱形继承会出现数据冗余问题,即man类中继承了两份 Person 的成员。
  • 并且会出现二义性,即使用Person中成员时,无法确认是使用的Student的还是Teacher的。
  • 虚继承可以很好的解决这个问题(virtual)

    • 在中间类的继承中加上virtual,子类在继承中间类时,只会继承一份Person类。

    C++继承_第2张图片

继承与组合

  • 继承:子类继承父类的成员,子类可以复用父类
  • 组合:子类中创建父类的对象,子类可以依据这个父类对象使用父类的公有成员
  • 建议尽量使用组合。
class Person
{}

class Student
{
    Person man;   //建立父类的对象,依靠这个对象使用父类成员。
}

你可能感兴趣的:(c++)