1. 程式人生 > >c++面向對象程序設計總結(類的使用)

c++面向對象程序設計總結(類的使用)

就是 height amp tput 分配 常成員函數 () .... 純虛函數

本篇算是學習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++面向對象程序設計總結(類的使用)