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

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;
}

可能以和還會更新吧..............