c++面向對象程序設計總結(類的使用)
本篇算是學習c++有關類的知識的一些易錯點吧.....
並不是特別詳細
幾點並不關於類的東西
1.函數模板,用虛擬類型來實現模板的功能
#include<iostream> using namespace std; template <typename t>//t為虛擬類型的名字,自己起的 t maxx(t a,t b,t c) { return max(a,max(b,c)); } int main() { double a=1.1,b=2.2,c=3.3;//不管為double 還是int都可以調用maxx cout<<maxx(a,b,c)<<endl;int a1=1,b1=2,c1=3; cout<<maxx(a1,b1,c1)<<endl; }
2.關於函數默認的參數值要放到最右邊
void f1(float a,int b=0,int c,char d=‘a‘);//錯誤, void f2(float a,int c,int b=0,char d=‘a‘);//正確
3.內置函數
函數最左邊加上inline(我覺得沒啥用),規模很小的函數才用
4.字符串
sizeof(string) 為4,因為系統分配的是固定的字節數,存放的是字符串的地址
.......(以後再補充把)
開始類的學習
1.三種類的類型
public
這個就不多說了,類的對外接口
private
想要訪問只能通過該類中的函數來訪問
protected
和private差不多,區別在於繼承時,以後說
2.類的聲明和成員函數的分離(以後更新)
3.構造函數
沒有返回值,名字和類名字一樣#include<iostream>
using namespace std; class box{ public: box(int ,int ,int );//構造函數 (有無默認參數都行) int volume(); private: int h;int w; int l; }; box::box(int a,int b,int c) { h=a,w=b,l=c; } //其實一般這樣寫 // box::box(int a,int b,int c):h(a),w(b),l(c){}
//註意如果是數組的話 則要寫在大括號內
//box::box(int a,int b,int c,char nam[]):h(a),w(b),l(c)
//{strcpy(name,nam);}
可以用另一個對象初始化另一個
time t1;
time t2=t1; //註意是吧t1的數據成員復制到t2,而不調用t2的構造函數
4.析構函數
註意一點,先構造的後析構,相當於棧,先進後出
靜態局部對象,在函數結束時,並不釋放,也就不調用析構函數
5.對象數組
box b[3] = (1 , 2 ,3)//這樣其實不對,這三個實參則分別作為3個元素的第一個實參
初始化應該
box a[3]={ box(10,20,30); box(20,30,40); box(1,2,3); }
6.對象指針
先說下函數指針。。。。還有函數指針????
類型名(* 指針變量名)(參數列表)
void (* p)();//p是一個指向void型函數的指針 p=fun;//fun函數入口地址付給p 註意沒有括號 (*p)();
對象成員函數有些復雜
要求 函數參數類型和個數匹配 函數返回值類型一樣 所屬的類一樣
void ( time:: *p )();//此時p為指向time類中的成員函數指針
time t; void (time:: *p)(); p = &time::gettime(); (t.*p)();
7.this指針(指向當前對象)
當前被調用的成員函數所在對象的起始地址
int box::volume() {return (h*l*w);}//實際為{ return this->h * this->l * this->w;}
調用時 如 a.volume() ,實際為將對象a的地址傳給形參this指針
8.常對象
只能通過構造函數參數表來對其初始化,所有數據成員絕對不能被改變,並且只能調用它的常成員函數
如果非要改變,要加上 mutable 如有一個計數變量count, 則要 mutable int count;
非const數據成員 非const函數可引用和改變 const函數可引用不可改變
const數據成員 非const函數可引用不可改變 const函數可引用不可改變
const函數不可調用非const函數
常指針 如
Time t1;
Time * const p = =&t1;
p不可再改變
常變量只能被常指針指向,,
普通變量也可被常指針指向,但這時該普通變量就在這期間變成的常變量,不能改變
復制構造函數
Box box2(box);
9.靜態數據成員
數據聲明前 加 static
特點是可以被每個該同類對象所引用,只能在類體外進行初始化,在類外也可直接引用
如 int Box::height = 10;//不必加static
可以通過對象名來引用,也可以通過類名
如
cout<<a.count<<endl;
cout<<Box::count<<endl;
10.友元
友元函數可以使一般的,也可以是另一個類中的,可以訪問私有數據成員
友元類就是全家都是友元函數
註意是單向的,註意不能傳遞
11.類的模板
temple<class t>//t 為虛擬變量名字 可以有多個,但都要加class 如:temple<class t1,class t2> class compare{ public: compare(t a,t b) { x=a,y=b; } t max() { return max(a,b); } private: t x,y; };
定義對象時為:
compare<int> cmp(3,4);
//多個時 compare<int ,double> cmp(3,4);
12.對運算符的重載
class yuan{ public: yuan(double a,double b):x(a),y(b){}; yuan operator +(yuan &t) { return yuan(x+t.x, y+t.y); } private: double x,y; };
此時如果有
yuan c1(1,2),c2(1,2),c3;
c3 = c1 + c2;
則實際為 c3 = c1.operator(c2);
但其實我覺得更方便的是通過友元函數
class yuan{ public: yuan(double a,double b):x(a),y(b){}; friend yuan operator +(yuan &t1,yuan &t2)//這個其實挺靈活的,可以自行改變 { return yuan(t1.x+t2.x, t1.y+t2.y); } private: double x,y; };
c3 = c1 + c2 則解釋為operator +(c1,c2);
13.繼承
派生類擁有基類的數據成員,其分配如下
先說公有繼承
基類屬性 派生類
private 不可訪問
public 公有繼承後 public
protected protected
私有繼承
基類屬性 派生類
private 不可訪問
public 私有繼承後 private
protected private
保護繼承
保護成員:只有子女(派生類)可以訪問,(友元函數也不行)
基類屬性 派生類
private 不可訪問
public 保護繼承後 protected
protected protected
14.有子對象的派生構造函數
#include<iostream> using namespace std; class Student{ public: void display(); Student(int n,string nam):num(n),name(nam){} protected: int num; string name; }; class Student1: public Student{ public: Student1(int n,string nam,int n1,string nam1,int a,string ad): Student(n,nam),monitor(n1,nam1),age(a),addr(ad){}//註意初始化,一般用初始化表來 ,同樣的,在多級派生中也是如此來構造 void show() { monitor.display(); } protected: Student monitor;//派生類中的子對象 int age; string addr; }; int main() { }
多級的形式
派生類構造名: 基類1構造函數(參數表) , 基類2構造函數(參數表) , 基類3構造函數(參數表)
{ 派生類中新增的數據成員初始化語句 }
15 . 關於多重繼承的二義性問題
就是繼承的函數名 和 派生的函數名一樣了
假設有類A和類B,此時類C同時繼承類A和類B,現在問題是 類A 類B 類C都有一個 叫display()的函數
C c1;
c1.display()//此時該是誰呢,是最新的也就是c的display()。這個會覆蓋
此時要想訪問A的display(),則要限定作用域 。
比如 c.A::display();
16.虛基類
D 是 B 和 C 的派生類,B 和 C 又都是繼承了A,這樣會保留多份數據成員的拷貝
虛基類是的在繼承簡介共同基類時只保留一份
class A { A(int i){} ..... }; class B: virtual public A { B(int n):A(n){} ... }; class C: virtual public A { C(int n):C(n){} ... }; class D:public B,public C { D(int n):A(n),B(n),C(n){}//這個必須由最後的派生類中對直接基類和虛基類初始化 }
17.類型的轉化
派生類可以向基類對象賦值 (大材小用),也可以向積累對象的引用進行賦值或初始化
派生類對象的地址可以賦給基類對象的指針變量,也就是說,指向基類對象的指針變量也可以用來指向派生類對象
18.多態性
分為兩種 ,靜態多態性和動態多態性(啥玩意啊,玩的怪花(小聲bb))
靜態多態性 就是 函數重載 和運算符的重載
動態 就是通過虛函數來實現的
說一下虛函數,作用還是要解決繼承中的二義性問題,
解決方法是想通過指針的方法來實現
Student stu(...); Graduate grad(...);//假設grad是stu的派生,且兩者都有display函數 Student *p = &stu; p->display(); p = &grad;//想通過變換指針指向來,但單單的這樣做是不行的,因為這樣做會把grad類型強制轉化成student的類型 p->display();
解決上述問題的方法是將Student類中的display()函數前加上virtual
註意問題是 成原函數 定義為虛函數後,其派生類都為虛函數
使用方法是指向一個基類對象的指針變量,並使它指向同一類族中需要調用該函數的對象
19.虛析構函數
如下面代碼
class Point{ public: point(); ~point(); }; class Circle: public Point { public: Circle(); ~Circle(); } int main() { Point *p = new Circle; delete p; return 0; }
new的一個對象,在釋放的時候,只會執行基類的析構函數,而不執行派生類的
解決方法是 在Point 的析構函數前加上 virtual
個人理解(這個virtual 在繼承中 都會遺傳)
20.純虛函數
先說一點吧,往往有一些類,他們不用來生成對象,唯一目的就是用它去建立派生類,叫做抽象類
比如,點 可以派生出 園 ,圓可以派生出圓柱體 ,但這些都是 shape 的直接派生或者間接派生
比如
class Shape{ public: virtual float area() const {return 0.0;}//虛函數 virtual float volume() const {return 0.0;}//虛函數 virtual void shapeName() const = 0; // 純虛函數 形式為 virtual 函數類型 函數名字 (參數列表) =0; };
最後來個差不多的
#include<iostream> using namespace std; class Shape { public: virtual float area() const {return 0.00;} virtual float volume() const {return 0.00;} virtual void ShapeName() const = 0; }; class Point: public Shape { public: Point(float a=0,float b=0): x(a), y(b){}; void SetPoint(float a,float b) { x=a,y=b; } float getX() const {return x;} float getY() const {return y;} virtual void ShapeName() const {cout<<"point"<<endl;} friend ostream &operator <<(ostream &,const Point &); protected: float x,y; }; ostream &operator <<(ostream &output,const Point &p) { output<<"["<<p.x<<","<<p.y<<"]"<<endl; return output; } class Circle: public Point { public: Circle(float x=0,float y=0,float r=0):Point(x,y),radius(r) {} void SetRaidus(float r){ radius = r;} float GetRadius() const {return radius;} virtual float area() const{ return 3.14 * radius * radius;} virtual void ShapeName() const {cout<<"Circle"<<endl;} friend ostream &operator <<(ostream &,const Circle &); protected: float radius; }; ostream &operator <<(ostream &out,const Circle &c) { out<<"["<<c.x<<" "<<c.y<<"]"<<endl; out<<"r="<<c.radius<<endl; return out; } class Yuan: public Circle { public: Yuan(float x=0,float y=0,float r=0,float h=0):Circle(x,y,r),height(h){} void SetHeight(float h) {height = h;} virtual float area() const {return 2 * Circle::area() + 2 * 3.14 * radius * height;} virtual float vulume() const {return Circle::area() * height;} virtual void ShapeName() const {cout<<"Yuan"<<endl;} friend ostream &operator <<(ostream &,const Yuan &); protected: float height; }; ostream & operator <<(ostream &out,const Yuan &Y) { out<<"["<<Y.x<<" "<<Y.y<<"],r="<<Y.radius<<"H="<<Y.height<<endl; return out; } int main() { Point point (3.2,4.5); Circle circle(2.4,1.2,5.6); Yuan yuan(3.4,6.4,5.2,10.5); point.ShapeName(); cout<<point<<endl; circle.ShapeName(); cout<<circle<<endl; yuan.ShapeName(); cout<<yuan<<endl; Shape *pt; pt=&point; pt->ShapeName(); pt=&circle; pt->ShapeName(); pt=&yuan; pt->ShapeName(); return 0; }
可能以和還會更新吧..............
c++面向對象程序設計總結(類的使用)