應該有一個星期沒寫了吧,原因之一是被數據結構實驗,需要編程,費時多。以後多抽時間寫吧。希望編輯完並發表沒有過12點。
2011-10-29(Objects and Classes)
1、類的定義格式一般如下:
class Student
{
private:
char name[20];
void addNum();
public:
void setName(char*);
char* getName();
void show();
};
注意最後的分號。這個定義和結構體相像,只是類中,成員默認的訪問控制是private而結構體是public,但爲了加強數據隱藏的概念,通常都顯式地使用private。通常的做法是,將類的定義寫在頭文件中,再用另一個cpp文件定義類中聲明的成員函數。定義函數時,有兩點要了解:①定義成員函數時要使用作用域操作符(::)來表示函數所屬的類;
②類方法可以訪問類的private。
**首先要提得是作用域的概念,即是可訪問的地方。如,靜態內部鏈接性的變量在整個源文件文件都是可訪問的,就說作用域是整個源文件。類的作用域,即是類成員函數體範圍的並集。由於函數中不能定義函數,所以定義函數是一般不在類作用域中,要加作用於操作符來定義函數:
void Student::setName(char* n)
{
strncpy_s(name,n,19);
}
當然,在類作用域中,不必使用::操作符:void Student::show()
{
cout << "Name: " << getName() << endl;
}
函數strncpy_s與strncpy功能一樣,不過微軟認爲後者會有危險,所以改寫了更安全的。這個函數的功能是,如果n的字符數小於等於第三個參數19,不足的用NULL補足,大於則自動截取19個字符賦給name。**成員函數可以訪問類的私有成員,所以成員函數是類對外的一個接口:
char* Student::getName(){ return name; }
當然也有私有函數的情況,但這種情況中,類作用域外不能訪問,一般用作內部數據的處理。比如在姓名後面加個學號,在類作用域中可以調用這個函數,而不必每次需要這個操作時都要編寫代碼實現。聽起來很像內聯函數,實際上,它就是內聯函數,定義位於類聲明的函數都會自動成爲內聯函數,如果在類中沒有定義函數體,可以在類的聲明後面定義(前面說過,內聯函數可以應在頭文件中定義)
inline void Student::addNum(){ std::cout << name << 5 << std::endl; }
當然不能在類中定義了的同時再用inline定義。
2、構造函數(Constructor)。
I、定義。與java類似(或言:java與C++類似),C++有構造函數對類成員初始化,不過與java不同的是,C++將構造函數的聲明和定義分開了,即:
//... ...
public:
Student(char* );
//... ...
Student::Student(char* m_name)
{
strncpy_s(name, m_name, 19);
}
**規則也差不多:當且僅當沒有顯式定義構造,編譯器自動添加默認構造函數。如果顯式定義了構造函數,則不能在使用默認構造函數了,如在上面的Student的構造定義後,下面的寫法是錯誤的:Student stu; //invalid
如果想這樣寫,必須提供默認構造函數,因爲在C++中有默認參數的概念,所以有下面兩種方法定義默認構造函數:
Student(); //default constructor
Student(char* m_name = "Tom"); //default constructor too
II、使用。三種方式:
Student s1 = Student("Karie"); //Form I
Student s2("Janne"); //Form II, the same as Student s2 = Student("Janne");
Student* s3 = new Student("Ace"); //Form III
3、折構函數(Destructior)。顧名思義,是用作清理對象的,在用new分配對象內存的時候用delete來釋放內存,如果不是用new生成對象,只需讓編譯器生成一個隱式的折構函數即可。**折構函數沒有參數,沒有返回值,爲了與構造函數加以區別,在類名前加上符號“~”,所以Student的折構函數原型必須是:
~Student();
它的函數體一般在類外面定義。
**折構函數不需顯式調用,編譯器會自動調用的(有例外,後面再談)。
4、類對象的一些操作。如果我們將折構函數定義並使用類Student如下:
Student::~Student()
{
std::cout << "Bye, " << name << std::endl;
}
int main()
{
Student s = Student("Tom");
s = Student("Karie");
s.show();
Student s1 = Student("Janne");
s = s1;
s.show();
s1.show();
return 0;
}
將有如下輸出:Bye, Karie
Name: Karie
Name: Janne
Name: Janne
Bye, Janne
Bye, Janne
①可用構造函數對已有對象進行覆蓋;
②可進行對象的複製;
③上面兩中操作將產生臨時對象,編譯器會使用折構函數清理。
5、const成員函數。如果這樣做:
const Student stu = Student("Tom");
s.show();
編譯器將報錯,因爲show()函數保證不了對象不被修改,雖然我們知道這個函數是不會修改對象的,但是編譯器不知道,所以要使用關鍵字const來做出保證:
void show() const; //function prototype
void Student::show()const{/*... ...*/} //function defined
這麼聲明後,show()將不能有一切不確定的可能改變對象的操作,比如,show()將不能調用非const成員函數。
6、this指針。this指針實際是所屬類的const型成員指針(比如這裏,this指針爲:Student* const this),指向的是對象本身。比如如果比較兩個對象名字字符串大小,並返回較大的,可以這樣寫:
Student Student::com(Student s)const
{
if(strcmp(this->name,s.name) >= 0)return *this;
else return s;
}
調用時,可以用如下兩種形式:const Student s1("Tom");
const Student s2("Som");
const Student top = s1.com(s2); //Form I
const Student top = s2.com(s1); //Form II
top.show();
7、對象數組。如果我們這樣寫:Student stu[4]; //implicit initialization
在程序沒有顯式地定義默認構造函數時,編譯器會使用函數體爲空的隱式默認構造函數對其初始化。也可以在聲明數組是顯式初始化:
Student stu[4] = {
Student("Tom"),
Student() //using default constructor
//... ...
};
今天筆記好像有點短,編個習題答案:
**定義類Country,包括國家名、人口、領土面積。使用此類,從讀入的一組國家數據中輸出:①領土最大的國家;②人口最多的國家;③人口密度最大的國家
//flieName: Country.h
#ifndef COUNN_H_
#define COUNN_H_
#include <string>
class Country
{
private:
std::string name;
int population; //Unit:people
double area; //Unit:square kilometer
double popuDensity()const{return population / area;}
public:
Country();
Country(std::string, int, double);
void show()const;
Country areaCompare(const Country)const;
Country popuCompare(const Country)const;
Country pdCompare(const Country)const;
};
#endif
//filenName: Country.cpp
#include <iostream>
#include "Country.h"
using namespace std;
Country::Country(string na, int popu, double ar)
{
name = na;
population = popu;
area = ar;
}
Country Country::areaCompare(const Country c)const
{
if(this->area > c.area)return *this;
else return c;
}
Country Country::popuCompare(const Country c)const
{
if(this->population > c.population)return *this;
else return c;
}
Country Country::pdCompare(const Country c)const
{
double thisPD = this->popuDensity();
double guestPD = c.popuDensity();
if(thisPD > guestPD)return *this;
else return c;
}
void Country::show()const
{
cout << "Conutry Name: " << name << endl;
cout << "Population: " << population << endl;
cout << "Territory Area: " << area << endl;
cout << "Population Density: " << popuDensity() << endl;
}
//fileName: Test.cpp
#include <iostream>
#include "Country.h"
using namespace std;
int main()
{
Country country[4] = {
Country("China", 1356800000, 9640000),
Country("Japan", 127767944, 377835),
Country("Russian", 141000000, 17075500),
Country("India", 1210200000,2980000)
};
Country top = country[0];
for(int i = 0; i< 4; i++)
top = top.areaCompare(country[i]);
cout << "Country of Max-area:\n";
top.show();
cout << endl;
for(int i = 0; i< 4; i++)
top = top.popuCompare(country[i]);
cout << "Country of Max-population:\n";
top.show();
cout << endl;
for(int i = 0; i< 4; i++)
top = top.pdCompare(country[i]);
cout << "Country of Max-population-density:\n";
top.show();
}