继承
-
基本概念
①.基类:可供其他类继承的类,基类的成员也将成为派生类的成员。
②.派生类:从基类继承而来的类,称为派生类。
③.虚函数:基类中希望其派生类可以定义自己版本的函数声明为虚函数,使用关键字 virtual 。
④.纯虚函数:在类内部声明虚函数时,在分号之前使用 =0,虚函数可用没有定义。
⑤.抽象基类:含有一个或者多个纯虚函数的类,无法创建抽象基类的对象。若派生类没有对继承的纯虚函数定义自己的版本,则派生类也是抽象的。
⑥.动态绑定:当使用基类的引用或者指针调用一个虚函数时,只有在运行时才能根据所绑定对象的实际类型来选择函数版本。
-
访问控制与继承
private 成员永远只能被本类成员函数或者本类友元访问;protected 成员只能被派生类访问。
①.public 继承:基类的非私有成员访问属性不变;基类的 public 成员还是 public ,基类的 protected 成员还是 protected ,基类的 private 成员不可访问。
class D 以 public 形式继承 class B,意味着 D 的对象同时也是一个 B 的对象,即 D 是 B 的一种,所有对 B 的操作都可以作用于 D,D 继承了 B 的接口和实现。
class B { public: int a; protected: int b; private: int c; public: B(int _a = 1,int _b = 2,int _c = 3):a(_a),b(_b),c(_c) {};//构造函数 }; class D:public B { public: D( int i):B(),d(i) {};//构造函数 void f() { cout << a << endl;//可以访问 cout << b << endl;//可以访问 cout << c << endl;//错误,基类私有成员不可访问 } private: int d; }; D d(1); cout << d.a << endl;//可以访问 cout << d.b << endl;//错误,基类受保护成员类外不可访问 cout << d.c << endl;//错误,基类的私有成员类外不可访问
②.protected 继承:基类的非私有成员在派生类都是受包含成员;基类的 public 成员变为 protected ,基类的 protected 成员还是 protected ,基类的 private 成员不可访问。
③.private 继承:基类的非私有成员在派生类都是私有成员;基类的 public 成员变为 private ,基类的 protected 成员变成 private ,基类的 private 成员不可访问。
class D 以 private 形式继承 class B,意味着只有实现部分被继承而接口被隐去,即 D 的对象根据 B 的对象的实现得到,即 D 和 B 没有任何概念上的关联关系。
class B { public: int a; protected: int b; private: int c; public: B(int _a = 1,int _b = 2,int _c = 3):a(_a),b(_b),c(_c) {};//构造函数 }; class D:private B { public: D( int i):B(),d(i) {};//构造函数 void f() { cout << a << endl;//可以访问 cout << b << endl;//可以访问 cout << c << endl;//错误,基类私有成员不可访问 } private: int d; }; D d(1); cout << d.a << endl;//错误,基础的成员变成私有成员,禁止类外访问 cout << d.b << endl;//错误,基类受保护成员类外不可访问 cout << d.c << endl;//错误,基类的私有成员类外不可访问
-
接口继承和实现继承
①.public 继承下,派生类总是会继承基类的所有接口;private 继承下,派生类仅继承实现,隐藏基类的接口
②.虚函数可以让派生类继承指定的接口和一份缺省的实现
③.虚函数可以让派生类继承指定的接口然后覆盖自己的实现
④.纯虚函数可以让派生类只继承指定的接口
⑤.纯虚函数可以让派生类只继承指定的接口,派生类可以主动继承基类实现
⑥.非虚函数可以让派生类继承指定的接口以及强制性的实现
-
类作用域
①.派生类的作用域位于基类作用域之内
因为派生类的作用域位于基类作用域之内,所以可以通过派生类可以像使用自己成员一样使用基类的成员。
②.派生类会隐藏掉基类中同名的成员
声明在内层作用域的函数不会重载声明在外层作用域的函数,因此派生类会因此作用域内同名的基类成员;隐藏规则仅和名称有关,和函数类型以及参数列表无关。
class B { public : virtual void f1() = 0; virtual void f1(int); void f2(); }; class D:public B { public : void f1(); void f2(int); }; D d; d.f1();//正确 d.f1(0);//错误,派生类中 f1 隐藏了基类中的重载版本 d.f2();错误,派生类中 f2 隐藏了基类中 f2 d.f2(0);//正确
-
构造与析构过程
①.构造过程
分配内存、依次调用父类的构造函数、根据成员变量的顺序依次调用成员的构造函数、执行构造函数体。
②.析构过程
执行析构函数、根据成员变量的顺序依次调用成员的析构函数、依次调用父类的析构函数、释放内存