继承:保留利用原有的类的功能; 派生:添加新的成员和功能。
派生类的构成:吸收基类成员、改造基类成员、添加新的成员。默认情况下派生类包含了全部基类函数中除构造函数和析构函数之外的所有成员,C++11规定可以用using语句继承基类构造函数。
一、继承方式
不同的继承方式的影响主要体现在:
1、派生类成员对基类成员的访问权限;
2、通过派生类对象对基类成员的访问权限。
对于派生类的成员或者派生类对象访问自己类的成员不讨论,跟一般类一样,下面只讨论对基类的成员的访问。
public:继承的访问控制:1、基类的public和protected成员:访问属性在派生类中保持不变;
2、基类的private成员:不可直接访问。
访问权限:1、派生类的成员函数,可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员;
2、通过派生类的对象,只能访问public成员。
private:继承的访问控制:1、基类的public和protected成员,都以private身份出现在派生类中;
2、基类的private成员:不可直接访问。
访问权限:1、派生类的成员函数,可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员;(调用基类的函数时,可用base::test().)
2、通过派生类的对象,不能访问从基类继承的任何成员。
protected:继承的访问控制:1、基类的public和protected成员:都以protected身份出现在派生类中;
2、基类的private成员:不可直接访问。
访问权限:1、派生类的成员函数,可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员;
2、通过派生类的对象,不能访问从基类继承的任何成员。
二、基类与派生类类型转换
1、公有派生类对象可以被当作基类的对象使用,反之则不可。
派生类的对象可以隐式转换为基类对象;
派生类的对象可以初始化基类的引用;
派生类的指针可以隐式转换为基类的指针。
2、通过基类对象名、指针只能使用从基类继承的成员、不能使用派生类的成员。(下面例子)
#include <iostream> using namespace std; class Base1 { //基类Base1定义 public: void display() const { cout << "Base1::display()" << endl; } }; class Base2: public Base1 { //公有派生类Base2定义 public: void display() const { cout << "Base2::display()" << endl; } }; class Derived: public Base2 { //公有派生类Derived定义 public: void display() const { cout << "Derived::display()" << endl; } }; void fun(Base1 *ptr) { //参数为指向基类对象的指针 ptr->display(); //"对象指针->成员名" } int main() { //主函数 Base1 base1; //声明Base1类对象 Base2 base2; //声明Base2类对象 Derived derived; //声明Derived类对象 fun(&base1); //用Base1对象的指针调用fun函数 fun(&base2); //用Base2对象的指针调用fun函数 fun(&derived); //用Derived对象的指针调用fun函数 return 0; }
建议不要重新定义继承而来的非虚函数!
三、派生类的构造和析构
默认情况下,基类的构造函数不被继承,派生类需要定义自己的构造函数。
C++11规定,可用using语句继承基类构造函数;但是只能初始化从基类继承的成员。语法形式: using Base::Base;
若不继承基类的构造函数:
派生类新增成员:派生类定义构造函数初始化;
继承来的成员:自动调用基类构造函数进行初始化;
派生类的构造函数需要给基类的构造函数传递参数;
样例:
#include<iostream> using namespace std; class B { public: B(); B(int i); ~B(); void print() const; private: int b; }; B::B() { b = 0; cout << "B's default constructor called." << endl; } B::B(int i) { b = i; cout << "B's constructor called." << endl; } B::~B() { cout << "B's destructor called." << endl; } void B::print() const { cout << b << endl; } class C : public B { public: C(); C(int i, int j); ~C(); void print() const; private: int c; }; C::C() { c = 0; cout << "C's default constructor called." << endl; } C::C(int i, int j) : B(i), c(j){ cout << "C's constructor called." << endl; } C::~C() { cout << "C's destructor called." << endl; } void C::print() const { B::print(); cout << c << endl; } int main() { C obj(5, 6); obj.print(); return 0; }