《程序設計實習》之【類和對象初探】

面向對象的程序設計方法



類的定義

class 類名
{
    訪問範圍說明符:
        成員變量1
        成員變量2
        …
        成員函數聲明1
        成員函數聲明2
    訪問範圍說明符:
        更多成員變量
        更多成員函數聲明
        …
};

從客觀事物抽象出來的例子

例: 客觀事物->類

寫一個程序, 輸入矩形的寬和高, 輸出面積和周長。

  • 矩形的屬性-寬和高
    • 兩個變量,分別代表寬和高
  • 對矩形的操作
    • 設置寬和高
    • 計算面積
    • 計算周長

class CRectangle {
public:
    int w, h;
    void Init( int w_, int h_ ) {           
        w = w_; h = h_;
    }
    int Area() {
        return w * h;
    }
    int Perimeter() {
        return 2 * ( w + h );
    }
}; //必須有分號
int main() {
    int w, h;
    CRectangle r; //r是一個對象
    cin >> w >> h;
    r.Init(w, h);
    cout << r.Area() << endl << r. Perimeter();
    return 0;
}

類定義的變量 ->類的實例 -> “對象”

對象的內存分配

  • 對象的內存空間
    • 對象的大小 = 所有成員變量的大小之和
    • E.g.CRectangle類的對象,sizeof(CRectangle)=8
  • 每個對象各有自己的儲存空間
    • 一個對象的某個成員變量被改變,不會影響到其他的對象

對象間的運算

  • 對象之間可以用=進行賦值
  • 不能用== != > < >= <=進行比較
    • 除非這些運算符經過了重載

訪問類的成員變量和成員函數

  • 用法1:對象名.成員名
CRectangle r1, r2;
r1.w = 5;
r2.Init(3,4);
  • 用法2:指針->成員名
CRectangle r1, r2;
CRectangle * p1 = & r1;
CRectangle * p2 = & r2;
p1->w = 5;
p2->Init(3,4); //Init作用在p2指向的對象上
  • 用法3:引用名.成員名
CRectangle r2;
CRectangle & rr = r2;
rr.w = 5;
rr.Init(3,4);  //rr的值變了,r2的值也變

另一種輸出結果的方式

void PrintRectangle(CRectangle & r) {
    cout << r.Area() << ","<< r.Perimeter();
}
CRectangle r3;
r3.Init(3,4);
PrintRectangle(r3);

類的成員函數的另一種方法

成員函數體和類的定義分開寫:

class CRectangle
{
public:
    int w, h;
    int Area();  //成員函數僅在此處聲明
    int Perimeter() ;
    void Init( int w_, int h_ );
};
int CRectangle::Area() {
    return w * h;
}
int CRectangle::Perimeter() {
    return 2 * ( w + h );
}
void CRectangle::Init( int w_, int h_ ) {
    w = w_; h = h_;
}

類成員的可訪問範圍

  • 關鍵字– 類成員可被訪問的範圍
    • private:指定私有成員, 只能在成員函數內被訪問
    • public:指定公有成員, 可以在任何地方被訪問
    • private:指定保護成員
  • 三種關鍵字出現的次數和先後次序都沒有限制
class className {
private:
    私有屬性和函數
public:
    公有屬性和函數
protected:
    保護屬性和函數
};

缺省爲私有成員

class Man {
    int nAge;   //私有成員
    char szName[20]; // 私有成員
public:
    void SetName(char * Name){
        strcpy(szName, Name);
    }
};
  • 類的成員函數內部, 可以訪問:
    • 當前對象的全部屬性, 函數
    • 同類其它對象的全部屬性, 函數
  • 類的成員函數以外的地方,

    • 只能夠訪問該類對象的公有成員
  • 設置私有成員的目的

    • 強制對成員變量的訪問一定要通過成員函數進行
  • 設置私有成員的機制 – 隱藏

內聯成員函數和重載成員函數

內聯成員函數

  • inline + 成員函數
  • 整個函數體出現在類定義內部
class B{
    inline void func1();   // 1
    void func2() {         // 2
    };
};

void B::func1() { }

成員函數的重載及參數缺省

  • 重載成員函數
  • 成員函數–帶缺省參數
#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; }
};
void Location::init( int X, int Y){
    x = X;
    y = Y;
}
int main() {
    Location A;
    A.init(5);
    A.valueX(5);
    cout << A.valueX();   // 輸出:5
    return 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

構造函數

基本概念

  • 成員函數的一種

    • 名字與類名相同,可以有參數,不能有返回值(void也不行)
    • 作用是對對象進行初始化,如給成員變量賦初值
    • 如果定義類時沒寫構造函數,則編譯器生成一個默認的無參數 的構造函數
      • 默認構造函數無參數,不做任何操作
  • 如果定義了構造函數,則編譯器
  • 對象生成時構造函數自動被調用。對象一旦生成,就再也不能在 其上執行構造函數
  • 一個類可以有多個構造函數

爲什麼需要構造函數:

  • 構造函數執行必要的初始化工作,有了構造函數,就不必專門再寫初始化函數,也不用擔心忘記調用初始化函數。
  • 有時對象沒被初始化就使用,會導致程序出錯。
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 { 
    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) 初始化
發佈了97 篇原創文章 · 獲贊 27 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章