類和對象
OOP第二課
- 1 類的構成
- 2 成員函數(shù)的聲明
- 2.1 普通成員函數(shù)形式
- 2.2 將成員函數(shù)以內聯(lián)函數(shù)的形式進行說明
- 3 對象的定義和使用
- 3.1 對象的定義
- 3.2 對象中成員的訪問
- 3.3 類成員的訪問屬性
- 3.4 類中成員的訪問方式
- 3.5 對象賦值語句
- 3.6 類的作用域
類(class)是面向對象程序設計的最基本的概念,是C++最強有力的特征,是進行封裝和數(shù)據隱藏的工具,它將一個數(shù)據結構與一個操作集緊密地結合起來。類對象是類的實例,用類對象模擬現(xiàn)實世界中的事物比用數(shù)據對象更確切。
1. 類的構成
1.1 從結構到類
結構是C的一種自定義的數(shù)據類型,它把相關聯(lián)的數(shù)據元素組成一個單獨的統(tǒng)一體。
例2.1有關日期結構的例子
#include <iostream.h>
struct Date {
int year;
int month;
int day;
};
int main()
{
Date date1;
date1.year=2003;
date1.month=8;
date1.day=25;
cout<<date1.year<<"."<<date1.month<<"."
<<date1.day<<endl;
return 0;
}
?class與struct的比較
- 類是C++對C中結構的擴展。
- C語言中的struct是數(shù)據成員集合,而C++中的類,則是數(shù)據成員和成員函數(shù)的集合。
- struct是用戶定義的數(shù)據類型,是一種構造數(shù)據類型。類和struct一樣,也是一種用戶定義的數(shù)據類型,是一種構造數(shù)據類型。
- C結構無法對數(shù)據進行保護和權限控制,所以結構中的數(shù)據是不安全的。C++中的類將數(shù)據和與之相關聯(lián)的數(shù)據封裝在一起,形成一個整體,具有良好的外部接口可以防止數(shù)據未經授權的訪問,提供了模塊間的獨立性。
1.2 類的構成
類的成員分兩部分:一部分對應數(shù)據的狀態(tài),稱為數(shù)據成員,另一部分為作用于該數(shù)據狀態(tài)的函數(shù),稱為成員函數(shù)。
類聲明的一般格式如下:
class 類名 {
public:
公有數(shù)據成員;
公有成員函數(shù);
protected:
保護數(shù)據成員;
保護成員函數(shù);
private:
私有數(shù)據成員;
私有成員函數(shù);
};
3個關鍵字: private 、protected 和public ,稱為訪問權限關鍵字。每個關鍵字下面又都可以有數(shù)據成員和成員函數(shù)。
private 部分稱為類的私有部分,這一部分的數(shù)據成員和成員函數(shù)稱為類的私有成員。私有成員只能由本類的成員函數(shù)訪問,而類外部的任何訪問都是非法的。
public 部分稱為類的公有部分,這部分的數(shù)據成員和成員函數(shù)稱為類的公有成員。公有成員可以由程序中的函數(shù)訪問,它對外是完全開放的。
protected 部分稱為類的保護部分,這部分的數(shù)據成員和成員函數(shù)稱為類的保護成員。保護成員可以由本類的成員函數(shù)訪問,也可以由本類的派生類的成員函數(shù)訪問,而類外的任何訪問都是非法的。
注意:
- (1) 類聲明格式中的3個部分并非一定要全有,但至少要有其中的一個部分。
- 一般一個類的數(shù)據成員應該聲明為私有成員,成員函數(shù)聲明為公有成員。
- (2) 類聲明中的
private 、protected 和public 三個關鍵字可以按任意順序出現(xiàn)任意次。但是,如果把所有的私有成員、保護成員和公有成員歸類放在一起,程序將更加清晰。
- (3)
private 處于類體中第一部分時, 關鍵字private 可以省略。
- (4) 數(shù)據成員可以是任何數(shù)據類型,但不能用自動(auto)、寄存器(register)或外部(extern)進行聲明。
- (5) 不能在類聲明中給數(shù)據成員賦值。C++規(guī)定,只有在類對象定義之后才能給數(shù)據成員賦初值
用一個類來描述日期,其形式如下:
class Date {
public:
void setDate(int y,int m,int d);
void showDate();
private:
int m_year;
int m_month;
int m_day;
};
2. 成員函數(shù)的聲明
成員函數(shù)的聲明通常采用以下兩種方式:
2.1 普通成員函數(shù)形式
即在類的聲明中只給出成員函數(shù)的原型,而成員函數(shù)體寫在類的外部。
返回類型 成員函數(shù) (參數(shù)列表);
類外定義的一般形式是:
返回類型 類名∷成員函數(shù)名(參數(shù)表)
{
// 函數(shù)體
}
例如, 以下是表示坐標點的類Coord的聲明
class Coord {
public:
void setCoord (int,int); // 設置坐標點
int getx(); // 取x坐標點
int gety(); // 取y坐標點
private:
int x,y;
};
void Coord∷setCoord(int a,int b){ x=a; y=b;}
int Coord::getx(){ return x;}
int Coord::gety(){ return y;}
內聯(lián)函數(shù)和外聯(lián)函數(shù)
類的成員函數(shù)可以分為內聯(lián)函數(shù)和外聯(lián)函數(shù)。
- 內聯(lián)函數(shù)是指那些定義在類體內的成員函數(shù),即該函數(shù)的函數(shù)體放在類體內。而說明在類體內,定義在類體外的成員函數(shù)叫外聯(lián)函數(shù)。外聯(lián)函數(shù)的函數(shù)體在類的實現(xiàn)部分。
- 內聯(lián)函數(shù)在調用時不是像一般函數(shù)那樣要轉去執(zhí)行被調用函數(shù)的函數(shù)體,執(zhí)行完成后再轉回調用函數(shù)中,執(zhí)行其后語句,而是在調用函數(shù)處用內聯(lián)函數(shù)體的代碼來替換,這樣將會節(jié)省調用開銷,提高運行速度。
- 內聯(lián)函數(shù)與帶參數(shù)的宏定義進行一下比較,它們的代碼效率是一樣的,但是內聯(lián)函數(shù)要優(yōu)于宏定義,因為內聯(lián)函數(shù)遵循函數(shù)的類型和作用域規(guī)則,它與一般函數(shù)更相近,在一些編譯器中,一旦關上內聯(lián)擴展,將與一般函數(shù)一樣進行調用,調試比較方便。
- 外聯(lián)函數(shù)變成內聯(lián)函數(shù)的方法很簡單,只要在函
數(shù)頭前面加上關鍵字inline就可以了。
2.2 將成員函數(shù)以內聯(lián)函數(shù)的形式進行說明
有兩種格式將成員函數(shù)聲明為類的內聯(lián)函數(shù):
- (1)隱式聲明 直接將函數(shù)聲明在類內部。
class Coord{
public:
void setCoord(int a,int b)
{ x=a; y=b;}
int getx()
{ return x;}
int gety()
{ retrun y;}
private:
int x,y;
};
在類聲明中只給出成員函數(shù)的原型,而成員函數(shù)體寫在類的外部。為了使它起內聯(lián)函數(shù)的作用,在成員函數(shù)返回類型前冠以關鍵字“inline”。
這種成員函數(shù)在類外定義的一般形式是:
inline 返回類型 類名::成員函數(shù)名(參數(shù)表)
{
// 函數(shù)體
}
class Coord{
public:
void setCoord(int,int);
int getx();
int gety();
private:
int x,y;
};
inline void Coord::setCoord(int a,int b)
{ x=a; y=b;}
inline int Coord::getx(){ return x;}
inline int Coord::gety(){ return y; }
說明
- (1)使用inline說明內聯(lián)函數(shù)時,必須使函數(shù)體和inline說明結合在一起,否則編譯器將它作為普通函數(shù)處理。
inline void Coord:: setCoord(int ,int);
// 不能說明這是一個內聯(lián)函數(shù)
- (2) 通常只有較短的成員函數(shù)才定義為內聯(lián)函數(shù),對較長的成員函數(shù)最好作為一般函數(shù)處理。
class Date{
public:
void showDate();
private:
int year;
int month;
int day;
};
inline void Date::showDate()
{cout<<year<<'.';<<month<<'.'<<day<<endl;}
3. 對象的定義和使用
類與對象的關系
通常我們把具有共同屬性和行為的事物所構成的集合叫做類。
在C++中,可以把相同數(shù)據結構和相同操作集的對象看成屬于同一類。
在C++中,類也是一種用戶自定義數(shù)據類型,類的對象可以看成是該類類型的一個實例,定義一個對象和定義一個變量相似。類與對象間的關系,可以用數(shù)據類型int和整型變量i之間的關系類比。
C++把類的變量叫做類的對象,對象也稱為類的實例。
3.1 對象的定義
對象的定義, 也稱對象的創(chuàng)建
在C++中可以用以下兩種方法定義對象:
(1) 在聲明類的同時,直接定義對象。
class Coord {
public:
void setCoord(int,int);
int getx();
int gety();
private:
int x,y;
} op1,op2;
(2) 聲明了類之后,在使用時再定義對象
class Coord {
//…
};
// …
main()
{
Coord op1,op2;
// …
}
說明:
- 在聲明類的同時定義的對象是一種全局對象,在它的生存期內任何函數(shù)都可以使用它。
- 聲明了一個類便聲明了一種類型,它并不接收和存儲具體的值,只作為生成具體對象的一種“樣板”,只有定義了對象后,系統(tǒng)才為對象分配存儲空間。
3.2 對象中成員的訪問
當定義了一個類的對象后,就可以訪問對象的成員了。在類的外部可以通過類的對象對公有成員進行訪問,訪問對象成員要使用操作符“.”。
訪問的一般形式是:
- 對象名.數(shù)據成員名
- 對象名.成員函數(shù)名(參數(shù)表)
其中“.”叫做對象選擇符,簡稱點運算符。
例2.2 使用類Coord的完整程序
#include<iostream.h>
class Coord {
public:
void setCoord(int a,int b)
{ x=a; y=b; }
int getx()
{ return x; }
int gety()
{ return y; }
private:
int x,y;
};
void main()
{
Coord op1,op2;
int i,j;
op1.setCoord(5,6); // 調用op1的setCoord(),初始化對象op1
op2.setCoord(7,8); // 調用op2的setCoord(),初始化對象op2
i=op1.getx(); // 調用op1的getx(),取op1的x值
j=op1.gety(); // 調用op1的gety(),取op1的y值
cout<<"op1 i= "<<i<<" op1 j= "<<j<<endl;
i=op2.getx(); // 調用op2的getx(),取op2的x值
j=op2.gety(); // 調用op2的gety(),取op2的y值
cout<<"op2 i= "<<i<<" op2 j= "<<j<<endl;
}
說明:
- 對象名.成員名實際上是一種縮寫形式,它表達的意義是:對象名.類名::成員名
void main( )
{
Date date1;
date1.setDate(2006,9,21);
//……
}
- 在類的內部所有成員之間都可以通過成員函數(shù)直接訪問,但是類的外部不能訪問對象的私有成員。
例2.3 一個存在錯誤的程序
#include <iostream.h>
class Date {
public:
void setDate(int y,int m,int d);
void showDate();
private:
int year;
int month;
int day;
};
void Date∷setDate(int y,int m,int d)
{
year=y;
month=m;
day=d;
}
inline void Date∷showDate()
{
cout<<year<<"."<<month<<"."<<day<<endl;
}
void main()
{
Date date1,date2;
cout<<"Date1 set and output:"<<endl;
date1.setDate(1998,4,28);
cout<<date1.year<<"."<<date1.month<<"."<<date1.day<<endl; //錯誤
date1.showDate();
cout<<"Date2 set and output: "<<endl;
date2.setDate(2002,11,14);
cout<<date2.year<<"."<<date2.month<<"."<<date2.day<<endl; //錯誤
date2.showDate();·
}
- 在定義對象時,若定義的是指向對象的指針,則訪問此對象的成員時,要用“->”操作符。
void main( )
{
Date *date3;
date3->setDate(2001,8,15);
//……
}
3.3 類成員的訪問屬性
類成員有三種訪問屬性:公有(public)、 私有(private) 和保護(protected) 。
- 說明為公有的成員不但可以被類中成員函數(shù)訪問;還可在類的外部,通過類的對象進行訪問。
- 說明為私有的成員只能被類中成員函數(shù)訪問,不能在類的外部,通過類的對象進行訪問。
- 說明為保護的成員除了類本身的成員函數(shù)可以訪問外,該類的派生類的成員也可以訪問,但不能在類的外部,通過類的對象進行訪問。類成員的訪問屬性
類的成員對類對象的可見性和對類的成員函數(shù)的可見性是不同的。
類的成員函數(shù)可以訪問類的所有成員,而類的對象對類的成員的訪問是受類成員的訪問屬性的制約的。
3.4 類中成員的訪問方式
- 類中成員互訪:直接使用成員名
- 類外訪問:使用“對象名.成員名”方式訪問 public 屬性的成員
class Sample{
public:
int k;
int geti(){return i;}
int getj(){return j;}int getk(){return k;}
private:
int i;
protected:
int j;
};
//……
Sample a; //定義類Sample的對象a
a.i; //非法,類Sample的對象a不能訪問類的私有成員i
a.j; //非法,類Sample的對象a不能訪問類的保護成員j
a.k; //合法,類Sample的對象a能訪問類的公有成員k
//……
一般來說,公有成員是類的對外接口,而私有成員和保護成員是類的內部數(shù)據和內部實現(xiàn),不希望外界訪問。
將類的成員劃分為不同的訪問級別有兩個好處:一是信息隱蔽,即實現(xiàn)封裝;二是數(shù)據保護,即將類的重要信息保護起來,以免其它程序不恰當?shù)匦薷摹?/p>
3.5 對象賦值語句
兩個同類型的變量之間可以相互賦值。同類型的對象間也可以進行賦值,當一個對象賦值給另一個對象時,所有的數(shù)據成員都會逐位拷貝。
例2.5
#include<iostream.h>
class abc{
public:
void init(int i,int j) { a=i; b=j; }
void show(){ cout<<a<<" "<<b<<endl; }
private:
int a,b;
};
main()
{
abc o1,o2;
o1.init(12,34);
o2=o1; // 將對象o1數(shù)據成員的值賦給對象o2
o1.show();
o2.show();
return 0;
}
說明:
- 在使用對象賦值語句進行對象賦值時,兩個對象的類型必須相同,如果對象的類型不同,編譯時將出錯。
- 兩個對象之間的賦值,僅僅使這些對象中數(shù)據成員相同,而兩個對象仍是分離的。
- 例2.5的對象賦值是通過缺省的賦值運算符函數(shù)實現(xiàn)的。
- 當類中存在指針時,使用缺省的賦值運算符進行對象賦值,可能會產生錯誤。
3.6 類的作用域
所謂類的作用域就是指在類聲明中的一對花括號所形成的作用域。
- 一個類的所有成員都在該類的作用域內,一個類的任何成員可以訪問該類的其他成員。
- 一個類的成員函數(shù)可以不受限制地訪問類的成員,而在類的外部,對該類的數(shù)據成員和成員函數(shù)的訪問則要受到一定的限制,有時甚至是不允許的,這體現(xiàn)了類的封裝功能。
例2.6 理解類的作用域
# include<iostream.h>
class myclass{
public:
int i;
void init(int);
void show(){ cout<<“i=” <<i<<endl;} // 可以訪問類中的數(shù)據成員i
};
void myclass::init(int si){ i=si;} // 可以訪問類中的數(shù)據成員i
int fun(){ return i; } // 非法,不能直接訪問類中的i
void main()
{
myclass ob;
ob.init(5); // 給數(shù)據成員i賦初值5
ob.show();
i=8; // 非法,不能直接訪問類中的i,可改寫成ob.i=8
ob.show();
}
|