c++類學習過程中的一些知識點

類的語法形式

class 類名稱
{
public:
    公有成員(外部接口)
private:
    私有成員
protected:
    保護型成員
};

公有成員:類與外部的接口,任何外部函數都可以訪問類內的公有數據類型和函數
私有成員:只允許本類的對象裏的成員訪問
保護成員:在繼承和派生上與私有成員有輕微差別
成員變量:類裏定義的變量,可以在類裏所有的函數裏使用這些變量
本地變量:函數裏定義的變量

class A
{
private:
    int a;
public:
    int Fun();
};
int A::Fun()
{
    int fun;
    a=1;
    fun=2;
    return fun;
}

成員變量: a
本地變量: fun
2.隱藏指針

class A
{
private:
    int a;
public:
     void f();
};
void A::f()
{
   a=1;
}
struct B
{
    int a;
};
void f(struct B *p)
{
    p->a=1;
}
int main()
{
    A a;
    B a;
    a.f();
    f(&a);
    return 0;
}

這裏的a.f()和f(&a)是一樣的,進入f這個函數的時候編譯器會自動加上This指針。
函數會變成這樣。這樣就可以區分是哪一個對象了。

void A::f()
{
   This->a=1;
}

類的構造與析構
c++中類裏定義的變量在定義對象的時候所指向的內存並不是乾淨的(java不是這樣的),這是由於c++爲了提高效率,類裏的變量既然要用到就一定要給它賦值,沒必要提前清理一遍,所以我們需要在類的構造函數裏把類初始化。
相應的,類似於指針,使用完後需要釋放其內存,對象也是如此,用構造函數創建對象後,程序負責跟蹤該對象,直到其過期爲止,對象過期時,程序將自動調用一個特殊的成員函數——析構函數

class X
{
    int i;
public:
    X();
    ~X();
};

這個X()就是構造函數。
(1)構造函數的名字和類的名字相同
(2)構造函數是沒有返回類型的(不能加返回類型,構造函數裏不能加return)
(3)一個對象被創造的時候其對應的類裏的構造函數就會被執行(也就是說如果有 X a的時候實際上會去做 a.X())
(4)如果構造函數有參數的話,定義一個對象的時候要加參數 如:X a(1)

這個~X()就是析構函數
(1)析構函數在出對象作用域的時候被執行。

4.c++的動態分配內存
在這裏插入圖片描述malloc分配的內存要用free來釋放,同樣的new分配的內存要用delete來釋放
delete[] p的意思是釋放掉int 數組大小的空間,如果不加[]的話只會釋放單個int大小的空間,在釋放空間的時候析構函數就會被執行。
5. struct 和 class 的區別

兩者區別在於

class A
{
    int a;
    int b;
public:
    int c;
};
struct A
{
    int a;
    int b;
public:
    int c;
};

在類裏沒有限制訪問屬性的部分,class會將其視爲private,而struct 會將其視爲public.

6.初始化
初始化方法一:類內初始化

class A
{
    int a=0;
public:
};

類內初始化順序晚於構造函數
初始化方法二:直接在構造函數裏進行初始化

class A
{
    int *p;
public:
    A()
    {
        p=NULL;
    }
};

初始化方法二:在構造函數括號後加上冒號給出要初始化變量的名字,再加一個括號,在括號里加上初始化變量的值。

#include<bits/stdc++.h>
using namespace std;
class point
{
public :
    void initpoint(double x=0,double y=0)
    {
        this->x=x;
        this->y=y;
    }
    double getX(){return x;}
    double getY(){return y;}
private:
    double x,y;
};
int main()
{
    point a;
    a.initpoint(1,2);
    cout<<a.getX()<<a.getY()<<endl;
}

這裏的double x=0,和double y=0是可以這樣寫的,如果在調用initpoint函數的時候沒有給參數,x和y就會被初始化爲0,如果給了參數,x和y就是參數那個值

函數缺省參數值

c++允許我們 在函數參數表裏預先給一個參數初始化一個值
比如 fun(int size,int initquantity = 0 );
fun(1);這樣寫是合法的
但是要注意 fun(int a=1,int b=2,int c)這樣是不對的,必須從右邊往左初始化,但是這種寫法只能寫在聲明裏

const
const int * p和int const *p 都是指p指向的數據是常數,不可以通過p來修改它所指向內存的數據
int *const p 是指指針是不能改變的,不能進行p++等操作,但是可以通過p來修改它所指向內存的數據

const的數據不能賦給非const的指針
非const的數據 可以賦給const的指針
怎麼來理解呢?
在語法上 可以通過非const的指針來修改 它所指向的值,但是如果它指向的那個值是個const定義的常數,語法就衝突了,所以const的數據不能賦給非const的指針,因此語法規定了const 類型的指針來保存const數據

子類對象可以當作父類對象用
父類對象裏面有的,子類對象都有,因此子類對象可以成爲父類對象成員函數的參數,子類對象裏多出來的東西相當於不存在。所以在子類使用複製構造函數的 時候,父類的複製構造函數的參數可以是子類對象的目標對象(要複製的那個對象)

虛函數表

#include<iostream>
using namespace std;
class A
{
    int i;
public :
    A():i(10){}
    virtual void f(){cout<<"A::f()"<<i<<endl;}
};
class B:public A
{
    int j;
public:
    B():j(20){}
    virtual void f(){cout<<"B::f()"<<j<<endl;}
};
int main()
{
    A a;
    B b;
    A *p=&b;
    p->f();

    a=b;
    p=&a;
    p->f();
    return 0;
}

輸出結果
在這裏插入圖片描述
我們用A類型的指針指向對象b,然後執行f函數,會執行b的,因爲虛函數表沒有改變,所以當我們把b的值賦給a的時候,由於虛函數表沒有改變,我們在執行
p->f()的時候,執行的是A類的f函數

int main()
{
    A a;
    B b;
    A *p=&a;
    int* r=(int*)&a;
    int* t=(int*)&b;
    *r = *t;
    p->f();
    return 0;
}

虛函數表的地址位於類的起始地址緊接着的地址
如果我們把主函數改成這樣
輸出結果會變成這樣在這裏插入圖片描述也就是說賦值的過程,不會改變虛函數表的地址
但是如果是 A a, B b,然後 b=a,這樣的話,執行 b->f()就會執行A::f了
在這裏插入圖片描述對象中的常數據成員只能通過初始化列表的形式來初始化

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章