C++基礎之對象的關係

1、變量

一、變量和類的生命週期
變量的生存期是指變量所佔據的內存空間由分配到釋放的時期。變量有效的範圍稱爲其做用域。全局變量是程序中定義在全部函數(包括main函數)以外的任何變量,其做用域
是程序從變量定義到整個程序結束的部分。這意味着全局變量能夠被全部定義在全局變量以後的函數訪問。全局變量及靜態變量分配的空間在全局數據區,它們的生存期爲整個程序的執行期間。
⚫ 而局部變量,如在函數內或程序塊內說明的變量,被分配到局部數據區,如棧區等。這種分配是臨時的,一旦該函數體或程序塊運行結束,所分配的空間就會被撤銷。局部變量的生存期從被說明處開始,到所在程序塊結束處結束。
⚫ 對於靜態變量,若是沒有進行初始化,系統會自動初始化爲0。局部變量若是沒有進行初始化,則其值是不肯定的。
⚫ 使用new運算符建立的變量具備動態生存期。從聲明處開始,直到用delete運算符釋放存儲空間或程序結束時,變量生存期結束。類的對象在生成時調用構造函數,在消亡時調用析構函數,在這兩個函數調用之間便是對象的生存期。數組

二、在類中,也可使用const關鍵字定義成員變量和成員函數,甚至是類的對象。由關鍵字const修飾的類成員變量稱爲類的常量成員變量。類的常量成員變量必須進行初始化,並且只能經過構造函數的成員初始化列表的方式進行。使用const修飾的函數稱爲常量函數。定義類的對象時若是在前面添加const關鍵字,則該對象稱爲常量對象。定義常量對象或常量成員變量的通常格式以下:
const 數據類型 常量名=表達式;
⚫ 定義常量函數的格式以下:類型說明符 函數名(參數表)const;
⚫ 在對象被建立之後,其常量成員變量的值就不容許被修改,只能夠讀取其值。對於常量對象,只能調用常量函數。總之,常量成員變量的值不能修改,常量對象中的各個屬性值均不能修改。
⚫ 不能經過常量對象調用普通成員函數 const Person person;person.getName();//錯誤的函數

 1、封閉類

當生成封閉類的對象並進行初始化時,它包含的成員對象也須要被初始化,須要調用成員對象的構造函數。在定義封閉類的構造函數時,須要添加初始化列表,指明要調用成員對象的哪一個構造函數。在封閉類構造函數中添加初始化列表的格式以下:
封閉類名::構造函數名(參數表): 成員變量1(參數表),成員變量2(參數表),…{…}
初始化列表中的成員變量既能夠是成員對象,也能夠是基本數據類型的成員變量。對於成員對象,初始化列表的「參數表」中列出的是成員對象構造函數的參數(它指明瞭該成員對象如何初始化)。
先調用成員對象的構造函數,再調用封閉類對象的構造函數。測試

二、封閉類的複製構造函數
若是封閉類的對象是用默認複製構造函數初始化的,那麼它包含的成員對象也會用複製構造函數初始化。this

//成績類
class Course{
    public:
        int id;
        string name;
        Course();
        Course(Course &course);
        Course(int id,string name);
};
Course::Course(Course &course){
    cout << "Course 複製構造函數" << endl;
    this->id=course.id;
    this->name=course.name;
}
Course::Course(int id,string name){
    this->id=id;
    this->name=name;
    cout << "Course 普通構造函數" << endl;
};
//學生類
class Student{
    public:
        int id;
        string name;
        //學生類中包含課程(Course),Student 稱爲封閉類
        Course course;
        Student(int id,string name,int cId,string cName);
        void show();   
};
Student::Student(int id,string name,int cId,string cName):id(id),name(name),course(cId,cName){
   cout << "Student 普通構造函數" << endl;
}
void Student::show(){
   cout << "name:"  << this->name  <<" course:" << this->course.name<< endl;
}
int main(){
    Student student(1,"小米",1,"數學");
    student.show();
    Student student2(2,"美團",1,"C++");
    student2.show();
}

 3、this指針

C++語言規定,當調用一個成員函數時,系統自動向它傳遞一個隱含的參數。該參數是一個指向調用該函數的對象的指針,稱爲this指針,從而使成員函數知道對哪一個對象進行操做。
⚫ C++規定,在非靜態成員函數內部能夠直接使用this關鍵字,this就表明指向該函數所做用的對象的指針。
⚫ 在通常狀況下,在不引發歧義時,能夠省略「this->」,系統採用默認設置。
⚫ 靜態成員是類具備的屬性,不是對象的特徵,this表示的是隱藏的對象的指針,因此靜態成員函數沒有this指針。spa

void Person::setName(string name){
    this->name=name;
}
string Person::getName(){
    return this->name;
}
void Person::setId(int id){
    this->id=id;
}
int Person::getId(){
    return this->id;
}

4、對象的性質 

一、同一類的對象之間能夠相互賦值,
  如語句:Point A,B; A.Setxy(25,55); B=A;
二、可使用對象數組,
  如語句:Point A[3]; 定義數組A能夠存儲3個Point類的對象。
三、也可使用指向對象的指針,使用取地址運算符&將一個對象的地址置於該指針中,
  如語句: Point * p=&A; p->Display();
四、對象能夠用做函數參數。
若是參數傳遞採用傳對象值的方式,會在傳值過程當中產生副本,即臨時對象,因此在被調用函數中對形參所做的改變不影響調用函數中做爲實參的對象。
若是採起傳對象的引用(傳地址)的方式,當形參對象被修改時,相應的實參對象也將被修改。若是採用傳對象地址值的方式,則使用對象指針做爲函數參數,效果與傳對象的引用同樣。
C++推薦使用對象的引用做爲參數傳遞,由於這樣不會產生副本(即臨時對象),在程序執行時不用調用構造函數,可直接進入函數體執行語句,在函數結束後,也不用調用析構函數析構臨時對象。如想避免被調用函數修改原來對象的數據成員,可以使用const修飾符。設計

  • void print(Point a){a.Display;} //對象做爲函數參數
  • void print(Point&a){a.Display;} //對象引用做爲函數參數
  • void print(Point * p){p->Display;} //對象指針做爲參數

它們的原型聲明分別爲:print(Point),print(Point&),print(Point *)。
對於對象A,print(&A)調用的是原型爲print(Point *)的函數形式。
另外,函數重載不能同時採用如上3種同名函數,由於函數使用的參數爲對象或對象引用時,編譯系統沒法區別這兩個函數,重載只能選擇其中的一種。指針

5、類的使用權限

使用類的權限
①類自己的成員函數可使用類的全部成員(私有和公有成員)。
②類的對象只能訪問公有成員函數。例如輸出x只能使用A.Getx(),不能使用A.x。
③其餘函數不能使用類的私有成員,也不能使用公有成員函數,它們只能經過定義類的對象爲本身的數據成員,而後經過類的對象使用類的公有成員函數。
④雖然一個類能夠包含另一個類的對象,但這個類也只能經過被包含的類的對象使用那個類的成員函數,經過成員函數使用數據成員。person 是 student的成員,student不能直接操做person中的屬性,只能 Student.person.成員的方式來操做person中的成員code

class Person{
    public:
        int id;
        string name;    
};
class Student{
    public:
        Person person;
}

6、不徹底的類的聲明

類不是內存中的物理實體,只有當使用類產生對象時,才進行內存分配,這種對象創建的過程稱爲實例化。
類必須在其成員使用以前先進行聲明。然而,有時也能夠在類沒有徹底定義以前就引用該類,此時將類做爲一個總體來使用,如聲明全局變量指針:對象

class MembersOnly; //不徹底的類聲明
MembersOnly * club; //定義全局變量類指針
Void main(){… 函數體} //主函數
class MembersOnly{…函數體}; //徹底定義該類

不徹底聲明的類不能實例化,不然會編譯出錯;不徹底聲明僅用於類和結構,企圖存取沒有徹底聲明的類成員,也會引發編譯錯誤。blog

7、空類:

儘管類的目的是封裝代碼和數據,它也能夠不包括任何聲明,如:class Empty{ }; 這種空類沒有任何行爲,但能夠產生空類對象。
在開發大的項目時,須要在一些類尚未徹底定義或實現時進行先期測試,定義空類可保證代碼能正確被編譯,從而容許先測試其中的一部分。此時常給空類增長一個無參數構造函數,以消除強類型檢查的編譯器產生的警告。如
class Empty{
  public:Empty(){ }
};

8、類做用域

①聲明類時所使用的一對花括號造成類做用域,在類做用域中聲明的標識符只在類中可見,如:class example { int num; } ;
  int i=num; //定義整型數i,並用num賦值;錯誤,由於num在類外並無定義,因此在此不可見
  int num; //從新定義整型數num;正確,由於此num是從新定義的一個整型數,與類中說明的數據成員num具備不一樣的做用域
②若是某成員函數的實現是在類定義以外給出的,則類做用域也包含該成員函數的做用域,所以,當在該成員函數內使用一個標識符時,編譯器會先在類定義域中尋找,以下例:

class Myclass {
    int number; //定義屬於類Myclass的整型數number
    public:
        void set(int);
};
int number; //這個number不屬於類Myclass
void Myclass::set(int i){
    number=i; //使用的是類Myclass中的標識符number
};

③類中的一個成員名能夠經過使用類名和做用域運算符來顯式的指定,稱爲成員名限定,例如: void Myclass::set(int i){   Myclass::number=i; //顯示指定訪問Myclass類中的標識符number }④在程序中,對象的生存期由對象說明來決定;類中各數據成員的生存期由對象的生存期決定,隨對象存在和消失。⑤使用struct關鍵字設計類與class相反,struct的默認控制權限是public,通常不用struct設計類,而是用struct設計只包含數據的結構,而後用這種結構做爲類的數據成員。

相關文章
相關標籤/搜索