继承和派生
继承:在定义一个新的类B时,如果该类与某个已有的类A相似(指的是B拥有A的全部特点),
那么就可以把A作为一个基类,而把B作为基类的一个派生类(也称子类).
派生类是通过对基类进行修改和扩充得到的。在派生类中,可以扩充新的成员变量和成员函数.
派生类一经定义后,可以独立使用,不依赖于基类.
派生类拥有基类的全部成员函数和成员变量,不论是private、protected、public.
在派生类的各个成员函数中,不能访问基类中的private成员。
派生类的写法
class 派生类名:public 基类名 { };
派生类对象的内存空间
派生类对象的体积,等于基类对象的体积,再加上派生类对象自己的成员变量的体积。
在派生类对象中,包含着基类对象,而且基类对象的存储位置位于派生类对象新增的成员变量之前。
/*001-继承和派生*/ #include<iostream> #include<string> // if did not include this file using namespace std; class CStudent { private: string name; string id; char gender; int age; public: void PrintInfo(); void SetInfo(const string & name_, const string & id_, int age_, char gender_); string GetName() { return name; } }; class CUndergraduateStudent :public CStudent { private: string department; public: void QualifiedForBaoyan() { cout << "qualified for baoyan" << endl; } void PrintInfo() { CStudent::PrintInfo();//调用基类的PrintInfo cout << "Department:" << department << endl; } void SetInfo(const string & name_, const string & id_, int age_, char gender_, const string & department_) { CStudent::SetInfo(name_, id_, age_, gender_);//调用基类的SetInfo department = department_; } };// 派生类的写法是:类名: public 基类名 void CStudent::PrintInfo() { cout << "name:" << name << endl; cout << "id:" << id << endl; cout << "age:" << age << endl; cout << "gender:" << gender << endl; } void CStudent::SetInfo(const string & name_, const string & id_, int age_, char gender_) { name = name_; id = id_; age = age_; gender = gender_; } int main() { CUndergraduateStudent s2; s2.SetInfo("harry potter", "1188", 19, 'm', "cs"); // "" 对应字符串 '' 对应字符 cout << s2.GetName() << " "; s2.QualifiedForBaoyan(); s2.PrintInfo(); while (1); return 0; }
继承关系和复合关系
复合关系的使用
基类/派生类同名成员 与Protected关键字
Note: 一般来说,基类和派生类不定义同名成员变量
访问范围说明符
基类的private成员: 可以被下列函数访问
•基类的成员函数
•基类的友员函数
基类的public成员: 可以被下列函数访问
•基类的成员函数
•基类的友员函数
•派生类的成员函数
•派生类的友员函数
•其他的函数
访问范围说明符: protected
基类的protected成员: 可以被下列函数访问
•基类的成员函数
•基类的友员函数
•派生类的成员函数可以访问当前对象的基类的保护成员
#include<iostream> using namespace std; 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; // 不能访问基类私有变量吗? i = 5; //引用的是派生类的 i base::i = 5; //引用的是基类的 i func();//派生类的 base::func();//基类的 } int main() { derived obj; obj.i = 1; obj.base::i; } /*基类/派生类同名成员 与Protected关键字*/ #include<iostream> using namespace std; class Father { private: int nPrivate; //私有成员 public: int nPublic; //公有成员 protected: int nProtected; // 保护成员 }; class Son:public Father { void AccessFather() { nPublic = 1; // ok nPrivate = 1; // wrong nProtected = 1; // OK, 访问从基类继承的protected成员 Son f; f.nProtected = 1; //wrong, f不是当前对象 } }; int main() { Father f; Son s; f.nPublic = 1; // Ok s.nPublic = 1; // Ok f.nProtected = 1; // error f.nPrivate = 1; // error s.nProtected = 1; // error s.nPrivate = 1; // error return 0; }
派生类的构造函数
派生类的构造函数
派生类对象 包含 基类对象
执行派生类构造函数之前, 先执行基类的构造函数
派生类交代基类初始化, 具体形式:
构造函数名(形参表): 基类名(基类构造函数实参表)
{
}
派生类的构造函数
class Bug {
private :
int nLegs; int nColor;
public:
int nType;
Bug (int legs, int color);
void PrintBug () { };
};
class FlyBug: public Bug { // FlyBug是Bug的派生类
int nWings;
public:
FlyBug(int legs, int color, int wings);
};
FlyBug fb (2,3,4);
在 创建 派生类的对象 时,
•需要调用 基类的构造函数:
初始化派生类对象中从基类继承的成员
•在执行一个派生类的构造函数之前,
总是先执行基类的构造函数
调用基类构造函数的两种方式
•显式方式:
派生类的构造函数中 基类的构造函数提供参数
derived::derived(arg_derived-list):base(arg_base-list)
•隐式方式:
派生类的构造函数中, 省略基类构造函数时
派生类的构造函数, 自动调用基类的默认构造函数 派生类的析构函数被执行时, 执行完派生类的析构函数后, 自动调用基类的析构函数
构造函数的调用顺序和析构函数是相反的
创建 派生类的对象 时, 执行 派生类的构造函数 之前:
•调用 基类 的构造函数
初始化派生类对象中从基类继承的成员
•调用 成员对象类 的构造函数
初始化派生类对象中成员对象
执行完 派生类的析构函数 后:
•调用 成员对象类 的析构函数
•调用 基类 的析构函数
析构函数的调用顺序与构造函数的调用顺序相反
/* 派生类的构造函数 */ #include<iostream> using namespace std; #if 0 class Bug { private: int nLegs; int nColor; public: int nType; Bug(int legs, int color); void PrintBug() {} }; class FlyBug :public Bug { int nWings; public: FlyBug(int legs, int color, int wings); }; Bug::Bug(int legs, int color) { nLegs = legs; nColor = color; } // 表达式中可以出现: FlyBug构造函数的参数 FlyBug::FlyBug(int legs, int color, int wings) :Bug(legs, color) { nWings = wings; } int main() { FlyBug fb(2, 3, 4); fb.PrintBug(); fb.nType = 1; //fb.nLegs = 2 while (1); return 0; } #endif /* 调用基类构造函数的两种方式 */ class Base { public: int n; Base(int i) :n(i) { cout << "base " << n << " constructed" << endl; } ~Base() { cout << "base " << n << " desstructed" << 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); while (1); return 0; } /* 包含成员对象的派生类的构造函数 */ class Skill { public: Skill(int n) { } }; class FlyBug :public Bug { int nWings; Skill sk1, sk2; public: //表达式中可以出现: FlyBug构造函数的参数, 常量 FlyBug(int legs, int color, int wings) :Bug(legs, color), sk1(5), sk2(color) { nWings = wings; } };
public继承的赋值兼容规则
class base { };
class derived : public base { };
base b;
derived d;
1)派生类的对象可以赋值给基类对象
b = d;
2) 派生类对象可以初始化基类引用
base & br = d;
3) 派生类对象的地址可以赋值给基类指针
base * pb = & d;
直接基类和间接基类
类A派生类B,类B派生类C,类C派生类D,……
–类A是类B的直接基类
–类B是类C的直接基类,类A是类C的间接基类
–类C是类D的直接基类,类A、B是类D的间接基类
在声明派生类时,只需要列出它的直接基类
–派生类沿着类的层次自动向上继承它的间接基类
–派生类的成员包括
•派生类自己定义的成员
•直接基类中的所有成员
•所有间接基类的全部成员
#include<iostream> using namespace std; 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; } }; class MoreDerived :public Derived { public: MoreDerived() :Derived(4) { cout << "more derived constructed" << endl; } ~MoreDerived() { cout << "more derived destructed" << endl; } }; int main() { MoreDerived obj; while (1); return 0; }