C++学习笔记-继承
類之間可以建立聯系,這就使得類可以有某種關系
類之間的關系
has-A:包含關系,一個類使用另一個已經定義好的類的數據
uses-A:使用關系,友元或者對象參數傳遞
is-A:是的關系,這就是繼承,具有傳遞性不具有對稱性
繼承是類之間定義的一種重要關系,一個B類繼承A類,或稱從類A派生類B,類A稱為基類(父類),類B稱為派生類(子類)
基類和派生類
類繼承關系的語法形式
class 派生類名:基類名表 {數據成員和成員函數聲明 };基類名表構成:訪問控制 基類名1, 訪問控制 基類名2,···, 訪問控制 基類名n
訪問控制 表示派生類對基類的繼承方式,使用關鍵字:
- public 公有繼承
- private 私有繼承
- protected 保護繼承
訪問控制
派生類對基類成員的使用,與繼承訪問控制和基類中成員性質有關
公有繼承:基類的公有成員 -> 派生類的公有成員,基類的保護成員 -> 派生類的保護成員
私有繼承:基類的公有成員和保護成員 -> 派生類的私有成員
保護繼承:基類的公有成員和保護成員 -> 派生類的保護成員
不論種方式繼承基類,派生類都不能直接使用基類的私有成員
重名成員
派生類定義了與基類同名的成員,在派生類中訪問同名成員時屏蔽了基類的同名成員
在派生類中使用基類的同名成員,顯式地使用類名限定符:
類名::成員
派生類中的靜態成員
基類定義的靜態成員,將被所有派生類共享
根據靜態成員自身的訪問特性和派生類的繼承方式,在類層次體系中具有不同的訪問性質
派生類中訪問靜態成員,用以下形式顯式說明:
通過類:類名::成員
通過對象:對象名.成員
基類的初始化
建立一個類層次后,通常創建某個派生類的對象,包括使用基類的數據和函數
C++提供一種機制,在創建派生類對象時用指定參數調用基類的構造函數來初始化派生類繼承基類的數據
派生類構造函數聲明為
構造函數執行順序:基類 -> 對象成員 -> 派生類
繼承的應用實例
#include <iostream> #include <iomanip>using namespace std;class Point {friend ostream &operator<< (ostream &, const Point &); public:Point(int = 0, int = 0);//帶默認參數的構造函數void setPoint(int, int);//對點坐標數據賦值int getX() const{return x;}int getY() const{return y;} protected:int x, y;//Point類的數據成員 };class Circle :public Point {friend ostream &operator<<(ostream &, const Circle &);//友員函數 public:Circle(double r = 0.0, int x = 0, int y = 0);//構造函數void setRadius(double);/*置半徑*/double getRadius() const;/*返回半徑*/double area() const;//返回面積 protected:double radius;//數據成員,半徑 };class Cylinder :public Circle {friend ostream & operator<<(ostream &, const Cylinder &);//友員函數 public:Cylinder(double h = 0.0, double r = 0.0, int x = 0, int y = 0);//構造函數void setHeight(double);/*置高度值*/double getHeight() const;/*返回高度值*/double area() const;/*返回面積*/double volume() const;/*返回體積*/ protected:double height;//數據成員,高度 };//Point 類的成員函數 //構造函數,調用成員函數對x,y作初始化 Point::Point(int a, int b) {setPoint(a, b); } //對數據成員置值 void Point::setPoint(int a, int b) { x = a;y = b; } //重載插入算符,輸出對象數據 ostream &operator<<(ostream &output, const Point &p) {output << '[' << p.x << "," << p.y << "]";return output; }//Circle 類的成員函數 //帶初始化式構造函數,首先調用基類構造函數 Circle::Circle(double r, int a, int b):Point(a, b) { setRadius(r); } //對半徑置值 void Circle::setRadius(double r) {radius = (r >= 0 ? r : 0); } // 返回半徑值 double Circle::getRadius() const { return radius; } // 計算并返回面積值 double Circle::area() const { return 3.14159 * radius * radius; } // 輸出圓心坐標和半徑值 ostream & operator<< (ostream &output, const Circle &c) {output << "Center = " << '[' << c.x << "," << c.y << "]" << "; Radius = "<< setiosflags(ios::fixed | ios::showpoint) << setprecision(2) << c.radius;return output; }//Cylinder 類的成員函數 //帶初始化式構造函數,首先調用基類構造函數 Cylinder::Cylinder(double h, double r, int x, int y):Circle(r, x, y) { setHeight(h); } // 對高度置值 void Cylinder::setHeight(double h) {height = (h >= 0 ? h : 0); } // 返回高度值 double Cylinder::getHeight() const {return height; } // 計算并返回圓柱體的表面積 double Cylinder::area() const {return 2 * Circle::area() + 2 * 3.14159*radius*height; } // 計算并返回圓柱體的體積 double Cylinder::volume() const {return Circle::area()*height; } // 輸出數據成員圓心坐標、半徑和高度值 ostream &operator<< (ostream &output, const Cylinder &cy) {output << "Center = " << '[' << cy.x << "," << cy.y << "]" << "; Radius = "<< setiosflags(ios::fixed | ios::showpoint) << setprecision(2) << cy.radius<< "; Height = " << cy.height << endl;return output; }int main() {Point p(72, 115);//定義點對象并初始化cout << "The initial location of p is " << p << endl;p.setPoint(10, 10);//置點的新數據值cout << "\nThe new location of p is " << p << endl;//輸出數據Circle c(2.5, 37, 43);//定義圓對象并初始化cout << "\nThe initial location and radius of c are\n" << c << "\nArea = " << c.area() << "\n";//置圓的新數據值c.setRadius(4.25);c.setPoint(2, 2);//輸出圓心坐標和圓面積cout << "\nThe new location and radius of c are\n" << c << "\nArea = " << c.area() << "\n";Cylinder cyl(5.7, 2.5, 12, 23);//定義圓柱體對象并初始化//輸出圓柱體各數據和表面積,體積cout << "\nThe initial location, radius ang height of cyl are\n" << cyl<< "Area = " << cyl.area() << "\nVolume = " << cyl.volume() << '\n';//置圓柱體的新數據值cyl.setHeight(10);cyl.setRadius(4.25);cyl.setPoint(2, 2);cout << "\nThe new location, radius ang height of cyl are\n" << cyl<< "Area = " << cyl.area() << "\nVolume = " << cyl.volume() << "\n";system("pause");return 0; }多繼承
一個類有多個直接基類的繼承關系稱為多繼承
多繼承聲明語法
類C可以根據訪問控制同時繼承類A和類B的成員,并添加自己的成員
class C:public A, public B多繼承的派生類構造和訪問
- 多個基類的派生類構造函數可以用初始式調用基類構造函數初始化數據成員
- 執行順序與單繼承構造函數情況類似。多個直接基類構造函數執行順序取決于定義派生類時指定的各個繼承基類的順序
- 一個派生類對象擁有多個直接或間接基類的成員。不同名成員訪問不會出現二義性。如果不同的基類有同名成員,派生類對象訪問時應該加以識別
e.g.
虛基類
如果一個派生類從多個基類派生,而這些基類又有一個共同的基類,則在對該基類中聲明的名字進行訪問時,可能產生二義性
class B { public:int b; }; class B1:public B { private:int b1; }; class B2:public B { private:int b2; }; class C:public B1, public B2 { public:int f(); private:int d; }; C c; c.B;// error c.B::b;// error,從哪里繼承的? c.B1::b;// ok,從B1繼承的 c.B2::b;// ok ,從B2繼承的建立 C 類的對象時,B 的構造函數將被調用兩次:一次由B1調用,另一次由 B2 調用,以初始化 C 類的對象中所包含的兩個 B 類的子對象
- 如果一個派生類從多個基類派生,而這些基類又有一個共同的基類,則在對該基類中聲明的名字進行訪問時,可能產生二義性
- 如果在多條繼承路徑上有一個公共的基類,那么在繼承路徑的某處匯合點,這個公共基類就會在派生類的對象中產生多個基類子對象
- 要使這個公共基類在派生類中只產生一個子對象,必須對這個基類聲明為虛繼承,使這個基類成為虛基類
- 虛繼承聲明使用關鍵字:virtual
由于類 C 的對象中只有一個 B 類子對象,名字 b 被約束到該子對象上,所以,當以不同路徑使用名字 b 訪問 B 類的子對象時,所訪問的都是那個唯一的基類子對象。即cc.B1::b 和cc.B2::b引用是同一個基類 B 的子對象
面向對象中的繼承指類之間的父子關系
C++中的繼承方式(public、private、protected)會影響子類的對外訪問屬性
- public繼承:父類成員在子類中保持原有訪問級別
- private繼承:父類成員在子類中變為private成員
- protected繼承:父類中public成員會變成protected,父類中protected成員仍然為protected,父類中private成員仍然為private
注意:private成員在子類中依然存在,但是卻無法訪問到。
繼承總結
- 繼承是面向對象程序設計實現軟件重用的重要方法。程序員可以在已有基類的基礎上定義新的派生類。
- 單繼承的派生類只有一個基類。多繼承的派生類有多個基類。
- 派生類對基類成員的訪問由繼承方式和成員性質決定。
- 創建派生類對象時,先調用基類構造函數初始化派生類中的基類成員。調用析構函數的次序和調用構造函數的次序相反。
- C++提供虛繼承機制,防止類繼承關系中成員訪問的二義性。
- 多繼承提供了軟件重用的強大功能,也增加了程序的復雜性
轉載于:https://www.cnblogs.com/cj5785/p/10664728.html
總結
以上是生活随笔為你收集整理的C++学习笔记-继承的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 3.2.7.1 替换细节
- 下一篇: s3c2440移植MQTT