c++类和对象初步
程序設計與算法(三)C++面向對象程序設計-郭煒 第二周
總結整理:
目錄:
- 1.類成員的可訪問范圍
- 2.成員函數的 重載及參數缺省
- 3.構造函數 (constructor)
- 4.復制構造函數 copy constructor
- 5.類型轉換構造函數
- 6.析構函數 destructors
1.類成員的可訪問范圍
在類的定義中,用下列訪問范圍關鍵字來說明類成員 可被訪問的范圍:
– private: 私有成員,只能在成員函數內訪問
– public : 公有成員,可以在任何地方訪問
– protected: 保護成員,以后再說
以上三種關鍵字出現的次數和先后次序都沒有限制
定義一個類
如過某個成員前面沒有上述關鍵字,則缺省地被認為 是私有成員。
class Man { int nAge; //私有成員 char szName[20]; // 私有成員 public: void SetName(char * szName){ strcpy( Man::szName,szName); } };在類的成員函數內部,能夠訪問:
– 當前對象的全部屬性、函數;
– 同類其它對象的全部屬性、函數。
在類的成員函數以外的地方,只能夠訪問該類對象的 公有成員。
class CEmployee { private: char szName[30]; //名字 public : int salary; //工資 void setName(char * name); void getName(char * name); void averageSalary(CEmployee e1,CEmployee e2); }; void CEmployee::setName( char * name) { strcpy( szName, name); //ok } void CEmployee::getName( char * name) { strcpy( name,szName); //ok } void CEmployee::averageSalary(CEmployee e1,CEmployee e2){ cout << e1.szName; //ok,訪問同類其他對象私有成員salary = (e1.salary + e2.salary )/2; } int main() { CEmployee e; strcpy(e.szName,"Tom1234567889"); //編譯錯,不能訪 問私有成員e.setName( "Tom"); // ok e.salary = 5000; //ok return 0; }設置私有成員的機制,叫“隱藏”
“隱藏”的目的是強制對成員變量的訪問一定要通過成員函數進行,那么以后成員變量的類型等屬性修改后,只需要更改成員函數即可。否則,所有直接訪問成員變量的語句都需要修改。
如果將上面的程序移植到內存空間緊張的手持設備上,希望將 szName 改為 char szName[5],若szName不是私有,那么就要找出所有類似strcpy(e.szName,”Tom1234567889”); 這樣的語句進行修改,以防止數組越界。這樣做很麻煩。
“隱藏”的作用
如果將szName變為私有,那么程序中就不可能出現(除非在類的內部) strcpy(e.szName,”Tom1234567889”); 這樣的語句,所有對 szName的訪問都是通過成員函數來進行,
比如:e.setName( “Tom12345678909887”);
那么,就算szName改短了,上面的語句也不需要找出來修改,只要改 setName成員函數,在里面確保不越界就可以了。
用struct定義類
struct CEmployee { char szName[30]; //公有!! public : int salary; //工資 void setName(char * name); void getName(char * name); void averageSalary(CEmployee e1,CEmployee e2); };和用”class”的唯一區別,就是未說明是公有還是私有的成員,就是 公有
2.成員函數的 重載及參數缺省
成員函數也可以重載
成員函數可以帶缺省參數
使用缺省參數要注意避免有函數重載時的二義性
class Location { private : int x, y; public: void init( int x =0, int y = 0 ); void valueX( int val = 0) { x = val; } int valueX() { return x; }}; Location A; A.valueX(); //錯誤,編譯器無法判斷調用哪個valueX3.構造函數 (constructor)
基本概念:
1. 成員函數的一種
2. 名字與類名相同,可以有參數,不能有返回值(void也不行)
3. 作用是對對象進行初始化,如給成員變量賦初值
4. 如果定義類時沒寫構造函數,則編譯器生成一個默認的無參數的構造函數
5. 默認構造函數無參數,不做任何操作
6. 如果定義了構造函數,則編譯器不生成默認的無參數的構造函數
7. 對象生成時構造函數自動被調用。對象一旦生成,就再也不能在其上執行構造函數
8.一個類可以有多個構造函數
為什么需要構造函數:
1) 構造函數執行必要的初始化工作,有了構造函數,就不 必專門再寫初始化函數,也不用擔心忘記調用初始化函數。
2) 有時對象沒被初始化就使用,會導致程序出錯
可以有多個構造函數,參數個數或類型不同
class Complex {private :double real, imag; public: void Set( double r, double i );Complex(double r, double i ); Complex (double r ); Complex (Complex c1, Complex c2); }; Complex::Complex(double r, double i) { real = r;imag = i; } Complex::Complex(double r) { real = r;imag = 0; } Complex::Complex (Complex c1, Complex c2); { real = c1.real+c2.real; imag = c1.imag+c2.imag; } Complex c1(3) , c2 (1,0), c3(c1,c2); // c1 = {3, 0}, c2 = {1, 0}, c3 = {4, 0};構造函數最好是public的,private構造函數 不能直接用來初始化對象
class CSample{ private: CSample() { } };int main(){ CSample Obj; //err. 唯一構造函數是private return 0; }構造函數 在數組中的使用
#include<iostream> using namespace std;class CSample { int x;public: CSample() { cout << "Constructor 1 Called" << endl; } CSample(int n) { x = n; cout << "Constructor 2 Called" << endl; }}; int main(){ CSample array1[2]; cout << "step1"<<endl; CSample array2[2] = {4,5}; cout << "step2"<<endl; CSample array3[2] = {3}; cout << "step3"<<endl; CSample * array4 = new CSample[2]; delete []array4; return 0;}//Constructor 1 Called //Constructor 1 Called //step1 //Constructor 2 Called //Constructor 2 Called //step2 //Constructor 2 Called //Constructor 1 Called //step3 //Constructor 1 Called //Constructor 1 Called class Test { public: Test( int n) { } //(1) Test( int n, int m) { } //(2) Test() { } //(3) }; Test array1[3] = { 1, Test(1,2) }; // 三個元素分別用(1),(2),(3)初始化Test array2[3] = { Test(2,3), Test(1,2) , 1}; // 三個元素分別用(2),(2),(1)初始化 Test * pArray[3] = { new Test(4), new Test(1,2) }; //兩個元素分別用(1),(2) 初始化4.復制構造函數 copy constructor
1.只有一個參數,即對同類對象的引用。
2.形如 X::X( X& )或X::X(const X &), 二者選一 后者能以常量對象作為參數
3.如果沒有定義復制構造函數,那么編譯器生成默認復制構造函數。默認的復制構造函數完成復制功能。
4.如果定義的自己的復制構造函數, 則默認的復制構造函數不存在
5.不允許有形如 X::X( X )的構造函數。
復制構造函數起作用的三種情況
1)當用一個對象去初始化同類的另一個對象時
2)如果某函數有一個參數是類 A 的對象, 那么該函數被調用時,類A的復制構造函數將被調用。
#include<iostream>using namespace std;class A { public: A() { }; A( A & a) { cout << "Copy constructor called" <<endl; } }; void Func(A a1){ } int main(){ A a2; Func(a2);return 0; } //程序輸出結果為: Copy constructor called3) 如果函數的返回值是類A的對象時,則函數返回時 A的復制構造函數被調用:
#include<iostream>using namespace std;class A { public: int v; A(int n) { v = n; }; A( const A & a) { v = a.v; cout << "Copy constructor called" <<endl; } }; A Func() { A b(4); return b; }int main() { cout << Func().v << endl; return 0; } //輸出結果: Copy constructor called 4對象間賦值并不導致復制構造函數被調用
#include<iostream> using namespace std;class CMyclass {public: int n; CMyclass() {}; CMyclass( CMyclass & c) { n = 2 * c.n ; } };int main() { CMyclass c1,c2; c1.n = 5; c2 = c1; CMyclass c3(c1); cout <<"c2.n=" << c2.n << ","; cout <<"c3.n=" << c3.n << endl; return 0; }// 輸出: c2.n=5,c3.n=10常量引用參數的使用
void fun(CMyclass obj_ ) { cout << "fun" << endl; }這樣的函數,調用時生成形參會引發復制構造函數調用,開銷比較大。
所以可以考慮使用 CMyclass & 引用類型作為參數。
如果希望確保實參的值在函數中不應被改變,那么可以加上const 關鍵字:
5.類型轉換構造函數
定義轉換構造函數的目的是實現類型的自動轉換。
只有一個參數,而且不是復制構造函數的構造函數,一般 就可以看作是轉換構造函數。
當需要的時候,編譯系統會自動調用轉換構造函數,建立 一個無名的臨時對象(或臨時變量)。
6.析構函數 destructors
1.名字與類名相同,在前面加‘~’, 沒有參數和返回值,一 個類最多只能有一個析構函數。
2.析構函數對象消亡時即自動被調用。可以定義析構函數來在 對象消亡前做善后工作,比如釋放分配的空間等。
3.如果定義類時沒寫析構函數,則編譯器生成缺省析構函數。 缺省析構函數什么也不做
4.如果定義了析構函數,則編譯器不生成缺省析構函數。
析構函數和數組
1.對象數組生命期結束時,對象數組的每個元素的析構函數都會被調用。
析構函數和運算符 delete
delete 運算導致析構函數調用
若new一個對象數組,那么用delete釋放時應該寫 []。否則只delete一個對 象(調用一次析構函數)
2.析構函數在對象作為函數返回值返回后被調用
#include<iostream> using namespace std;class CMyclass {public: ~CMyclass() { cout << "destructor" << endl; } }; CMyclass obj; CMyclass fun(CMyclass sobj )//參數對象消亡也會導致析構函數被調用 (1) { return sobj; //函數調用返回時生成臨時對象返回 } int main(){ obj = fun(obj); //函數調用的返回值(臨時對象)被用過后,該臨時對象析構函數被調(2)return 0; //(3)函數結束時class類全局變量消亡,析構函數被調用 } //destructor //destructor //destructor構造函數和析構函數什么時候被調用?
總結
- 上一篇: python range 步长为负数_【
- 下一篇: 计算机中丢失msc,mscvr120.d