日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++类和对象初步

發布時間:2025/3/12 c/c++ 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++类和对象初步 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

程序設計與算法(三)C++面向對象程序設計-郭煒 第二周
總結整理:

目錄:

      • 1.類成員的可訪問范圍
      • 2.成員函數的 重載及參數缺省
      • 3.構造函數 (constructor)
      • 4.復制構造函數 copy constructor
      • 5.類型轉換構造函數
      • 6.析構函數 destructors

1.類成員的可訪問范圍

在類的定義中,用下列訪問范圍關鍵字來說明類成員 可被訪問的范圍:
– private: 私有成員,只能在成員函數內訪問
– public : 公有成員,可以在任何地方訪問
– protected: 保護成員,以后再說

以上三種關鍵字出現的次數和先后次序都沒有限制
定義一個類

class className { 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.成員函數的 重載及參數缺省

成員函數也可以重載
成員函數可以帶缺省參數

#include <iostream> using namespace std; class Location { private : int x, y; public: void init( int x=0 , int y = 0 ); void valueX( int val ) { x = val ;} int valueX() { return x; }int valueY() { return y; }}; void Location::init( int X, int Y) { x = X; y = Y; } int main() { Location A,B; A.init(5);//賦值,x=5,y=0cout << A.valueX()<<endl;//5A.valueX(6); //x=6,y=0cout << A.valueX()<<','<<A.valueY(); //6,0return 0; }

使用缺省參數要注意避免有函數重載時的二義性

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(); //錯誤,編譯器無法判斷調用哪個valueX

3.構造函數 (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 c1; //默認構造函數被調用 Complex * pc = new Complex; //默認構造函數被調用 class Complex { private : double real, imag; public: Complex( double r, double i = 0); }; Complex::Complex( double r, double i) //寫了一個構造函數 { real = r; imag = i; } Complex c1; // error, 缺少構造函數的參數 Complex * pc = new Complex; // error, 沒有參數Complex c1(2); // OK Complex c1(2,4), c2(3,5); Complex * pc = new Complex(3,4);

可以有多個構造函數,參數個數或類型不同

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 )的構造函數。

class Complex { private : double real,imag; }; Complex c1; //調用缺省無參構造函數 Complex c2(c1);//調用缺省的復制構造函數,將 c2 初始化成和c1一樣 4: class Complex { public : double real,imag; Complex(){ } Complex( const Complex & c ) { real = c.real; imag = c.imag; cout << “Copy Constructor called”; } }; Complex c1; Complex c2(c1);//調用自己定義的復制構造函數,輸出 Copy Constructor called 5: class CSample { CSample( CSample c ) { } //錯,不允許這樣的構造函數 };

復制構造函數起作用的三種情況
1)當用一個對象去初始化同類的另一個對象時

Complex c2(c1); Complex c2 = c1; //初始化語句,非賦值語句 /* 賦值操作是在兩個已經存在的對象間進行的, 而初始化是要創建一個新的對象,并且其初值來源于另一個已存在的對象。 編譯器會區別這兩種情況,賦值的時候調用重載的賦值運算符, 初始化的時候調用拷貝構造函數。 如果類中沒有拷貝構造函數,則編譯器會提供一個默認的。 這個默認的拷貝構造函數只是簡單地復制類中的每個成員 */

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 called

3) 如果函數的返回值是類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 關鍵字:

void fun(const CMyclass & obj) { //函數中任何試圖改變 obj值的語句都將是變成非法 }

5.類型轉換構造函數

定義轉換構造函數的目的是實現類型的自動轉換。
只有一個參數,而且不是復制構造函數的構造函數,一般 就可以看作是轉換構造函數。
當需要的時候,編譯系統會自動調用轉換構造函數,建立 一個無名的臨時對象(或臨時變量)。

#include<iostream> using namespace std;class Complex { public: double real, imag; Complex( int i) {//類型轉換構造函數 cout << "IntConstructor called" << endl; real = i; imag = 0; } Complex(double r,double i) {real = r; imag = i; } }; int main () { Complex c1(7,8); Complex c2 = 12; c1 = 9; // 9被自動轉換成一個臨時Complex對象 cout << c1.real << "," << c1.imag << endl; return 0; } //IntConstructor called //IntConstructor called //9,0

6.析構函數 destructors

1.名字與類名相同,在前面加‘~’, 沒有參數和返回值,一 個類最多只能有一個析構函數。
2.析構函數對象消亡時即自動被調用。可以定義析構函數來在 對象消亡前做善后工作,比如釋放分配的空間等。
3.如果定義類時沒寫析構函數,則編譯器生成缺省析構函數。 缺省析構函數什么也不做
4.如果定義了析構函數,則編譯器不生成缺省析構函數。

class String{ private : char * p; public: String () { p = new char[10]; } ~ String () ; }; String ::~ String() { delete [] p; }

析構函數和數組
1.對象數組生命期結束時,對象數組的每個元素的析構函數都會被調用。

#include<iostream> using namespace std;class Ctest { public: ~Ctest() { cout<< "destructor called" << endl; }}; int main () { Ctest array[2]; cout << "End Main" << endl; return 0; } //End Main //destructor called //destructor called

析構函數和運算符 delete
delete 運算導致析構函數調用

Ctest * pTest; pTest = new Ctest; //構造函數調用 delete pTest; //析構函數調用1次 pTest = new Ctest[3]; //構造函數調用3次 delete [] pTest; //析構函數調用3次

若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

構造函數和析構函數什么時候被調用

總結

以上是生活随笔為你收集整理的c++类和对象初步的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。