C++学习--继承和派生


一、概念

  1. 继承:在定义一个新的类B时,如果该类与某个已有的类A相似(指的是B拥有A的全部特点),那么就可以把A作为一个基类,而把B作为基类的一个派生类(也称子类)。
  2. 派生类是通过对基类进行修改和扩充得到的。在派生类中,可以扩充新的成员变量和成员函数。
  3. 派生类一经定义后,可以独立使用,不依赖于基类。
  4. 派生类拥有基类的全部成员函数和成员变量,不论是private、protected、public 。
  5. 在派生类的各个成员函数中,不能访问基类中的private成员。
    派生类的写法:
    class 派生类名:public 基类名 { };
    例如:
class CStudent {
private:
    string sName;
    int nAge;
public:
    bool IsThreeGood() {};
    void SetName(const string &name) { sName = name; }
};

class CUndergraduateStudent : public CStudent {
private:
    int nDepartment;
public:
    bool IsThreeGood() {}; //覆盖
    bool CanBaoYan() {};
};

class CGraduatedStudent : public CStudent {
private:
    int nDepartment;
    char szMentorName[20];
public:
    int CountSalary() {};
};

二、派生类对象的内存空间

派生类对象的体积,等于基类对象的体积,再加上派生类对象自己的成员变量的体积。在派生类对象中,包含着基类对象,而且基类对象的存储位置位于派生类对象新增的成员变量之前。

class CBase
{
	int v1,v2;
};
class CDerived:public CBase
{
	int v3;
};

在这里插入图片描述


三、派生类覆盖基类成员

派生类可以定义一个和基类成员同名的成员,这叫覆盖。在派生类中访问这类成员时,缺省的情况是访问派生类中定义的成员。要在派生类中访问由基类定义的同名成员时,要使用作用域符号::。
例如:

class base {
    int j;
public:
    int i;
    void func();
};

class derived :public base{
public:
    int i;
    void access();
    void func();
};

void derived::access() {
//    j = 5; //error
    i = 5; //引用的是派生类的 i
    base::i = 5; //引用的是基类的 i
    func(); //派生类的
    base::func(); //基类的
}

int main() {
    derived obj;
    obj.i = 1;
    obj.base::i = 1;
    return 0;
}

四、类的保护成员

  1. 基类的private成员:可以被下列函数访问

    • 基类的成员函数
    • 基类的友元函数
  2. 基类的public成员:可以被下列函数访问

    • 基类的成员函数
    • 基类的友元函数
    • 派生类的成员函数
    • 派生类的友元函数
    • 其他的函数
  3. 基类的protected成员:可以被下列函数访问

    • 基类的成员函数
    • 基类的友元函数
    • 派生类的成员函数可以访问当前对象的基类的保护成员

五、派生类的构造函数

  1. 在创建派生类的对象时,需要调用基类的构造函数:初始化派生类对象中从基类继承的成员。在执行一个派生类的构造函数之前,总是先执行基类的构造函数。
  2. 调用基类构造函数的两种方式

– 显式方式:在派生类的构造函数中,为基类的构造函数提供参数.
derived::derived(arg_derived-list):base(arg_base-list)
– 隐式方式:在派生类的构造函数中,省略基类构造函数时,派生类的构造函数则自动调用基类的默认构造函数.

  1. 派生类的析构函数被执行时,执行完派生类的析构函数后,自动调用基类的析构函数。
class Base {
public:
    int n;
    Base(int i):n(i)
    { cout << "Base " << n << " constructed" << endl;}
    ~Base()
    { cout << "Base " << n << " destructed" << endl; }
};
class Derived:public Base {
public:
    Derived(int i):Base(i)
    { cout << "Derived constructed" << endl; }
    ~Derived()
    { cout << "Derived destructed" << endl;}
};
int main() {
    Derived Obj(3); return 0;
}
打印:
Base 3 constructed
Derived constructed
Derived destructed
Base 3 destructed

  1. 包含成员对象的派生类的构造函数写法
class Bug {
private :
    int nLegs; int nColor;
public:
    int nType;
    Bug ( int legs, int color);
    void PrintBug (){ };
};
class Skill {
public:
    Skill(int n) { }
};
class FlyBug: public Bug {
    int nWings;
    Skill sk1, sk2;
public:
    FlyBug( int legs, int color, int wings);
};
FlyBug::FlyBug(int legs, int color, int wings): Bug(legs,color), sk1(5), sk2(color),nWings(wings) {}


六、封闭派生类对象的构造函数执行顺序

在创建派生类的对象时:

  1. 先执行基类的构造函数,用以初始化派生类对象中从基类继承的成员;
  2. 再执行成员对象类的构造函数,用以初始化派生类对象中成员对象。
  3. 最后执行派生类自己的构造函数

在派生类对象消亡时:

  1. 先执行派生类自己的析构函数
  2. 再依次执行各成员对象类的析构函数
  3. 最后执行基类的析构函数

析构函数的调用顺序与构造函数的调用顺序相反。


七、赋值兼容规则

1.public继承的赋值兼容规则

class base { };
class derived : public base { };
base b;
derived d;
  1. 派生类的对象可以赋值给基类对象
    b = d;
  2. 派生类对象可以初始化基类引用
    base & br = d;
  3. 派生类对象的地址可以赋值给基类指针
    base * pb = & d;
  4. 如果派生方式是 private或protected,则上述三条不可行。

2.protected继承和private继承

class base {
};
class derived : protected base {
};
base b;
derived d;
  1. protected继承时,基类的public成员和protected成员成为派生类的protected成员。
  2. private继承时,基类的public成员成为派生类的private成员,基类的protected成员成为派生类的不可访问成员。
  3. protected和private继承不是“是”的关系。

八、直接基类和间接基类

  1. 在声明派生类时,只需要列出它的直接基类

     – 派生类沿着类的层次自动向上继承它的间接基类
     – 派生类的成员包括
     	• 派生类自己定义的成员
     	• 直接基类中的所有成员
     	• 所有间接基类的全部成员
    

总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值