C++結構體and類 & 物件 Day3
本文來自http://www.runoob.com/cplusplus/cpp-operators.html
感謝!!!
C++ 資料結構
C/C++ 陣列允許定義可儲存相同型別資料項的變數,但是結構是 C++ 中另一種使用者自定義的可用的資料型別,它允許您儲存不同型別的資料項。
結構用於表示一條記錄,假設您想要跟蹤圖書館中書本的動態,您可能需要跟蹤每本書的下列屬性:
- Title :標題
- Author :作者
- Subject :類目
- Book ID :書的 ID
定義結構
為了定義結構,您必須使用 struct 語句。struct 語句定義了一個包含多個成員的新的資料型別,struct 語句的格式如下:
struct type_name {
member_type1 member_name1;
member_type2 member_name2;
member_type3 member_name3;
.
.
} object_names;
type_name 是結構體型別的名稱,member_type1 member_name1 是標準的變數定義,比如 int i; 或者 float f; 或者其他有效的變數定義。在結構定義的末尾,最後一個分號之前,您可以指定一個或多個結構變數,這是可選的。下面是宣告一個結構體型別 Books,變數為 book:
struct Books { char title[50]; char author[50]; char subject[100]; int book_id; } book;
訪問結構成員
為了訪問結構的成員,我們使用成員訪問運算子(.)。成員訪問運算子是結構變數名稱和我們要訪問的結構成員之間的一個句號。
下面的例項演示了結構的用法:
#include <iostream> #include <cstring> using namespace std; // 宣告一個結構體型別 Books struct Books { char title[50]; char author[50]; char subject[100]; int book_id; }; int main( ) { Books Book1; // 定義結構體型別 Books 的變數 Book1 Books Book2; // 定義結構體型別 Books 的變數 Book2 // Book1 詳述 strcpy( Book1.title, "C++ 教程"); //char strcpy( Book1.author, "Runoob"); //char strcpy( Book1.subject, "程式語言"); //char Book1.book_id = 12345; //int 賦值 // Book2 詳述 strcpy( Book2.title, "CSS 教程"); strcpy( Book2.author, "Runoob"); strcpy( Book2.subject, "前端技術"); Book2.book_id = 12346; // 輸出 Book1 資訊 cout << "第一本書標題 : " << Book1.title <<endl; //變數名.資料項 cout << "第一本書作者 : " << Book1.author <<endl; cout << "第一本書類目 : " << Book1.subject <<endl; cout << "第一本書 ID : " << Book1.book_id <<endl; // 輸出 Book2 資訊 cout << "第二本書標題 : " << Book2.title <<endl; cout << "第二本書作者 : " << Book2.author <<endl; cout << "第二本書類目 : " << Book2.subject <<endl; cout << "第二本書 ID : " << Book2.book_id <<endl; return 0; }
例項中定義了結構體類似 Books 及其兩個變數 Book1 和 Book2。當上面的程式碼被編譯和執行時,它會產生下列結果:
第一本書標題 : C++ 教程
第一本書作者 : Runoob
第一本書類目 : 程式語言
第一本書 ID : 12345
第二本書標題 : CSS 教程
第二本書作者 : Runoob
第二本書類目 : 前端技術
第二本書 ID : 12346
結構作為函式引數
您可以把結構作為函式引數,傳參方式與其他型別的變數或指標類似。您可以使用上面例項中的方式來訪問結構變數:
#include <iostream>
#include <cstring>
using namespace std;
void printBook( struct Books book ); //宣告以結構體作為形參的函式
// 宣告一個結構體型別 Books
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main( ) //主函式
{
Books Book1; // 定義結構體型別 Books 的變數 Book1
Books Book2; // 定義結構體型別 Books 的變數 Book2
// Book1 詳述
strcpy( Book1.title, "C++ 教程");
strcpy( Book1.author, "Runoob");
strcpy( Book1.subject, "程式語言");
Book1.book_id = 12345;
// Book2 詳述
strcpy( Book2.title, "CSS 教程");
strcpy( Book2.author, "Runoob");
strcpy( Book2.subject, "前端技術");
Book2.book_id = 12346;
// 輸出 Book1 資訊
printBook( Book1 ); //呼叫結構體函式
// 輸出 Book2 資訊
printBook( Book2 );
return 0;
}
void printBook( struct Books book )
{
cout << "書標題 : " << book.title <<endl;
cout << "書作者 : " << book.author <<endl;
cout << "書類目 : " << book.subject <<endl;
cout << "書 ID : " << book.book_id <<endl;
}
當上面的程式碼被編譯和執行時,它會產生下列結果:
書標題 : C++ 教程
書作者 : Runoob
書類目 : 程式語言
書 ID : 12345
書標題 : CSS 教程
書作者 : Runoob
書類目 : 前端技術
書 ID : 12346
指向結構的指標
您可以定義指向結構的指標,方式與定義指向其他型別變數的指標相似,如下所示:
struct Books *struct_pointer; //定義時帶*
現在,您可以在上述定義的指標變數中儲存結構變數的地址。為了查詢結構變數的地址,請把 & 運算子放在結構名稱的前面,如下所示:
struct_pointer = &Book1;
為了使用指向該結構的指標訪問結構的成員,您必須使用 -> 運算子,如下所示:
struct_pointer->title;
讓我們使用結構指標來重寫上面的例項,這將有助於您理解結構指標的概念:
#include <iostream>
#include <cstring>
using namespace std;
void printBook( struct Books *book ); //不同點在把book換成了指標*book
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main( )
{
Books Book1; // 定義結構體型別 Books 的變數 Book1
Books Book2; // 定義結構體型別 Books 的變數 Book2
// Book1 詳述
strcpy( Book1.title, "C++ 教程");
strcpy( Book1.author, "Runoob");
strcpy( Book1.subject, "程式語言");
Book1.book_id = 12345;
// Book2 詳述
strcpy( Book2.title, "CSS 教程");
strcpy( Book2.author, "Runoob");
strcpy( Book2.subject, "前端技術");
Book2.book_id = 12346;
// 通過傳 Book1 的地址來輸出 Book1 資訊
printBook( &Book1 );
// 通過傳 Book2 的地址來輸出 Book2 資訊
printBook( &Book2 );
return 0;
}
// 該函式以結構指標作為引數
void printBook( struct Books *book )
{
cout << "書標題 : " << book->title <<endl;
cout << "書作者 : " << book->author <<endl;
cout << "書類目 : " << book->subject <<endl;
cout << "書 ID : " << book->book_id <<endl;
}
當上面的程式碼被編譯和執行時,它會產生下列結果:
書標題 : C++ 教程
書作者 : Runoob
書類目 : 程式語言
書 ID : 12345
書標題 : CSS 教程
書作者 : Runoob
書類目 : 前端技術
書 ID : 12346
typedef 關鍵字
下面是一種更簡單的定義結構的方式,您可以為建立的型別取一個"別名"。例如
typedef struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
}Books;
現在,您可以直接使用 Books 來定義 Books 型別的變數,而不需要使用 struct 關鍵字。下面是例項:
Books Book1, Book2;
您可以使用 typedef 關鍵字來定義非結構型別,如下所示:
typedef long int *pint32;
pint32 x, y, z;
x, y 和 z 都是指向長整型 long int 的指標。
C++ 類 & 物件
C++ 在 C 語言的基礎上增加了面向物件程式設計,C++ 支援面向物件程式設計。類是 C++ 的核心特性,通常被稱為使用者定義的型別。
類用於指定物件的形式,它包含了資料表示法和用於處理資料的方法。類中的資料和方法稱為類的成員。函式在一個類中被稱為類的成員。
C++ 類定義
定義一個類,本質上是定義一個數據型別的藍圖。這實際上並沒有定義任何資料,但它定義了類的名稱意味著什麼,也就是說,它定義了類的物件包括了什麼,以及可以在這個物件上執行哪些操作。
類定義是以關鍵字 class 開頭,後跟類的名稱。類的主體是包含在一對花括號中。類定義後必須跟著一個分號或一個宣告列表。例如,我們使用關鍵字 class 定義 Box 資料型別,如下所示:
class Box
{
public:
double length; // 盒子的長度
double breadth; // 盒子的寬度
double height; // 盒子的高度
};
關鍵字 public 確定了類成員的訪問屬性。在類物件作用域內,公共成員在類的外部是可訪問的。您也可以指定類的成員為 private 或 protected,這個我們稍後會進行講解。
定義 C++ 物件
類提供了物件的藍圖,所以基本上,物件是根據類來建立的。宣告類的物件,就像宣告基本型別的變數一樣。下面的語句聲明瞭類 Box 的兩個物件:
Box Box1; // 宣告 Box1,型別為 Box
Box Box2; // 宣告 Box2,型別為 Box
物件 Box1 和 Box2 都有它們各自的資料成員。
訪問資料成員
類的物件的公共資料成員可以使用直接成員訪問運算子 (.) 來訪問。為了更好地理解這些概念,讓我們嘗試一下下面的例項:
#include <iostream>
using namespace std;
class Box
{
public:
double length; // 長度
double breadth; // 寬度
double height; // 高度
};
int main( )
{
Box Box1; // 宣告 Box1,型別為 Box
Box Box2; // 宣告 Box2,型別為 Box
double volume = 0.0; // 用於儲存體積
// box 1 詳述
Box1.height = 5.0;
Box1.length = 6.0;
Box1.breadth = 7.0;
// box 2 詳述
Box2.height = 10.0;
Box2.length = 12.0;
Box2.breadth = 13.0;
// box 1 的體積
volume = Box1.height * Box1.length * Box1.breadth;
cout << "Box1 的體積:" << volume <<endl;
// box 2 的體積
volume = Box2.height * Box2.length * Box2.breadth;
cout << "Box2 的體積:" << volume <<endl;
return 0;
}
當上面的程式碼被編譯和執行時,它會產生下列結果:
Box1 的體積:210
Box2 的體積:1560
需要注意的是,私有的成員和受保護的成員不能使用直接成員訪問運算子 (.) 來直接訪問。我們將在後續的教程中學習如何訪問私有成員和受保護的成員。
C++ 類成員函式
類的成員函式是指那些把定義和原型寫在類定義內部的函式,就像類定義中的其他變數一樣。類成員函式是類的一個成員,它可以操作類的任意物件,可以訪問物件中的所有成員。
讓我們看看之前定義的類 Box,現在我們要使用成員函式來訪問類的成員,而不是直接訪問這些類的成員:
class Box
{
public:
double length; // 長度
double breadth; // 寬度
double height; // 高度
double getVolume(void);// 返回體積
};
成員函式可以定義在類定義內部,或者單獨使用範圍解析運算子 :: 來定義。在類定義中定義的成員函式把函式宣告為內聯的,即便沒有使用 inline 識別符號。所以您可以按照如下方式定義 Volume() 函式:
class Box
{
public:
double length; // 長度
double breadth; // 寬度
double height; // 高度
double getVolume(void)
{
return length * breadth * height;
}
};
您也可以在類的外部使用範圍解析運算子 :: 定義該函式,如下所示:
double Box::getVolume(void)
{
return length * breadth * height;
}
在這裡,需要強調一點,在 :: 運算子之前必須使用類名。呼叫成員函式是在物件上使用點運算子(.),這樣它就能操作與該物件相關的資料,如下所示:
Box myBox; // 建立一個物件
myBox.getVolume(); // 呼叫該物件的成員函式
讓我們使用上面提到的概念來設定和獲取類中不同的成員的值:
#include <iostream>
using namespace std;
class Box
{
public:
double length; // 長度
double breadth; // 寬度
double height; // 高度
// 成員函式宣告
double getVolume(void);
void setLength( double len );
void setBreadth( double bre );
void setHeight( double hei );
};
// 成員函式定義
double Box::getVolume(void)
{
return length * breadth * height;
}
void Box::setLength( double len )
{
length = len;
}
void Box::setBreadth( double bre )
{
breadth = bre;
}
void Box::setHeight( double hei )
{
height = hei;
}
// 程式的主函式
int main( )
{
Box Box1; // 宣告 Box1,型別為 Box
Box Box2; // 宣告 Box2,型別為 Box
double volume = 0.0; // 用於儲存體積
// box 1 詳述
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// box 2 詳述
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
// box 1 的體積
volume = Box1.getVolume();
cout << "Box1 的體積:" << volume <<endl;
// box 2 的體積
volume = Box2.getVolume();
cout << "Box2 的體積:" << volume <<endl;
return 0;
}
C++ 類訪問修飾符
資料封裝是面向物件程式設計的一個重要特點,它防止函式直接訪問類型別的內部成員。類成員的訪問限制是通過在類主體內部對各個區域標記 public、private、protected 來指定的。關鍵字 public、private、protected 稱為訪問修飾符。
一個類可以有多個 public、protected 或 private 標記區域。每個標記區域在下一個標記區域開始之前或者在遇到類主體結束右括號之前都是有效的。成員和類的預設訪問修飾符是 private。
class Base {
public:
// 公有成員
protected:
// 受保護成員
private:
// 私有成員
};
公有(public)成員
公有成員在程式中類的外部是可訪問的。您可以不使用任何成員函式來設定和獲取公有變數的值,如下所示:
#include <iostream>
using namespace std;
class Line
{
public:
double length;
void setLength( double len );
double getLength( void );
};
// 成員函式定義
double Line::getLength(void)
{
return length ;
}
void Line::setLength( double len )
{
length = len;
}
// 程式的主函式
int main( )
{
Line line;
// 設定長度
line.setLength(6.0);
cout << "Length of line : " << line.getLength() <<endl;
// 不使用成員函式設定長度
line.length = 10.0; // OK: 因為 length 是公有的
cout << "Length of line : " << line.length <<endl;
return 0;
}
當上面的程式碼被編譯和執行時,它會產生下列結果:
Length of line : 6
Length of line : 10
私有(private)成員
私有成員變數或函式在類的外部是不可訪問的,甚至是不可檢視的。只有類和友元函式可以訪問私有成員。
預設情況下,類的所有成員都是私有的。例如在下面的類中,width 是一個私有成員,這意味著,如果您沒有使用任何訪問修飾符,類的成員將被假定為私有成員:
class Box
{
double width;
public:
double length;
void setWidth( double wid );
double getWidth( void );
};
實際操作中,我們一般會在私有區域定義資料,在公有區域定義相關的函式,以便在類的外部也可以呼叫這些函式,如下所示:
#include <iostream>
using namespace std;
class Box
{
public:
double length;
void setWidth( double wid );
double getWidth( void );
private:
double width;
};
// 成員函式定義
double Box::getWidth(void)
{
return width ;
}
void Box::setWidth( double wid )
{
width = wid;
}
// 程式的主函式
int main( )
{
Box box;
// 不使用成員函式設定長度
box.length = 10.0; // OK: 因為 length 是公有的
cout << "Length of box : " << box.length <<endl;
// 不使用成員函式設定寬度
// box.width = 10.0; // Error: 因為 width 是私有的
box.setWidth(10.0); // 使用成員函式設定寬度
cout << "Width of box : " << box.getWidth() <<endl;
return 0;
}
當上面的程式碼被編譯和執行時,它會產生下列結果:
Length of box : 10
Width of box : 10
保護(protected)成員
保護成員變數或函式與私有成員十分相似,但有一點不同,保護成員在派生類(即子類)中是可訪問的。
在下一個章節中,您將學習到派生類和繼承的知識。現在您可以看到下面的例項中,我們從父類 Box 派生了一個子類 smallBox。
下面的例項與前面的例項類似,在這裡 width 成員可被派生類 smallBox 的任何成員函式訪問。
C++ 類建構函式 & 解構函式
類的建構函式
類的建構函式是類的一種特殊的成員函式,它會在每次建立類的新物件時執行。
建構函式的名稱與類的名稱是完全相同的,並且不會返回任何型別,也不會返回 void。建構函式可用於為某些成員變數設定初始值。
下面的例項有助於更好地理解建構函式的概念:
#include <iostream>
using namespace std;
class Line
{
public:
void setLength( double len );
double getLength( void );
Line(); // 這是建構函式
private:
double length;
};
// 成員函式定義,包括建構函式
Line::Line(void)
{
cout << "Object is being created" << endl;
}
void Line::setLength( double len )
{
length = len;
}
double Line::getLength( void )
{
return length;
}
// 程式的主函式
int main( )
{
Line line;
// 設定長度
line.setLength(6.0);
cout << "Length of line : " << line.getLength() <<endl;
return 0;
}
當上面的程式碼被編譯和執行時,它會產生下列結果:
Object is being created
Length of line : 6
帶引數的建構函式
預設的建構函式沒有任何引數,但如果需要,建構函式也可以帶有引數。這樣在建立物件時就會給物件賦初始值,如下面的例子所示:
#include <iostream>
using namespace std;
class Line
{
public:
void setLength( double len );
double getLength( void );
Line(double len); // 這是建構函式
private:
double length;
};
// 成員函式定義,包括建構函式
Line::Line( double len)
{
cout << "Object is being created, length = " << len << endl;
length = len;
}
void Line::setLength( double len )
{
length = len;
}
double Line::getLength( void )
{
return length;
}
// 程式的主函式
int main( )
{
Line line(10.0);
// 獲取預設設定的長度
cout << "Length of line : " << line.getLength() <<endl;
// 再次設定長度
line.setLength(6.0);
cout << "Length of line : " << line.getLength() <<endl;
return 0;
}
當上面的程式碼被編譯和執行時,它會產生下列結果:
Object is being created, length = 10
Length of line : 10
Length of line : 6
使用初始化列表來初始化欄位
使用初始化列表來初始化欄位:
Line::Line( double len): length(len)
{
cout << "Object is being created, length = " << len << endl;
}
上面的語法等同於如下語法:
Line::Line( double len)
{
length = len;
cout << "Object is being created, length = " << len << endl;
}
假設有一個類 C,具有多個欄位 X、Y、Z 等需要進行初始化,同理地,您可以使用上面的語法,只需要在不同的欄位使用逗號進行分隔,如下所示:
C::C( double a, double b, double c): X(a), Y(b), Z(c)
{
....
}
類的解構函式
類的解構函式是類的一種特殊的成員函式,它會在每次刪除所建立的物件時執行。
解構函式的名稱與類的名稱是完全相同的,只是在前面加了個波浪號(~)作為字首,它不會返回任何值,也不能帶有任何引數。解構函式有助於在跳出程式(比如關閉檔案、釋放記憶體等)前釋放資源。
下面的例項有助於更好地理解解構函式的概念:
#include <iostream>
using namespace std;
class Line
{
public:
void setLength( double len );
double getLength( void );
Line(); // 這是建構函式宣告
~Line(); // 這是解構函式宣告
private:
double length;
};
// 成員函式定義,包括建構函式
Line::Line(void)
{
cout << "Object is being created" << endl;
}
Line::~Line(void)
{
cout << "Object is being deleted" << endl;
}
void Line::setLength( double len )
{
length = len;
}
double Line::getLength( void )
{
return length;
}
// 程式的主函式
int main( )
{
Line line;
// 設定長度
line.setLength(6.0);
cout << "Length of line : " << line.getLength() <<endl;
return 0;
}
當上面的程式碼被編譯和執行時,它會產生下列結果:
Object is being created
Length of line : 6
Object is being deleted
C++ 指向類的指標
一個指向 C++ 類的指標與指向結構的指標類似,訪問指向類的指標的成員,需要使用成員訪問運算子 ->,就像訪問指向結構的指標一樣。與所有的指標一樣,您必須在使用指標之前,對指標進行初始化。
下面的例項有助於更好地理解指向類的指標的概念:
#include <iostream>
using namespace std;
class Box
{
public:
// 建構函式定義
Box(double l=2.0, double b=2.0, double h=2.0)
{
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
}
double Volume()
{
return length * breadth * height;
}
private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
int main(void)
{
Box Box1(3.3, 1.2, 1.5); // Declare box1
Box Box2(8.5, 6.0, 2.0); // Declare box2
Box *ptrBox; // Declare pointer to a class.
// 儲存第一個物件的地址
ptrBox = &Box1;
// 現在嘗試使用成員訪問運算子來訪問成員
cout << "Volume of Box1: " << ptrBox->Volume() << endl;
// 儲存第二個物件的地址
ptrBox = &Box2;
// 現在嘗試使用成員訪問運算子來訪問成員
cout << "Volume of Box2: " << ptrBox->Volume() << endl;
return 0;
}
當上面的程式碼被編譯和執行時,它會產生下列結果:
Constructor called.
Constructor called.
Volume of Box1: 5.94
Volume of Box2: 102
C++ 類的靜態成員
我們可以使用 static 關鍵字來把類成員定義為靜態的。當我們宣告類的成員為靜態時,這意味著無論建立多少個類的物件,靜態成員都只有一個副本。
靜態成員在類的所有物件中是共享的。如果不存在其他的初始化語句,在建立第一個物件時,所有的靜態資料都會被初始化為零。我們不能把靜態成員的初始化放置在類的定義中,但是可以在類的外部通過使用範圍解析運算子 :: 來重新宣告靜態變數從而對它進行初始化,如下面的例項所示。
下面的例項有助於更好地理解靜態成員資料的概念:
#include <iostream>
using namespace std;
class Box
{
public:
static int objectCount;
// 建構函式定義
Box(double l=2.0, double b=2.0, double h=2.0)
{
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
// 每次建立物件時增加 1
objectCount++;
}
double Volume()
{
return length * breadth * height;
}
private:
double length; // 長度
double breadth; // 寬度
double height; // 高度
};
// 初始化類 Box 的靜態成員
int Box::objectCount = 0;
int main(void)
{
Box Box1(3.3, 1.2, 1.5); // 宣告 box1
Box Box2(8.5, 6.0, 2.0); // 宣告 box2
// 輸出物件的總數
cout << "Total objects: " << Box::objectCount << endl;
return 0;
}
當上面的程式碼被編譯和執行時,它會產生下列結果:
Constructor called.
Constructor called.
Total objects: 2
靜態成員函式
如果把函式成員宣告為靜態的,就可以把函式與類的任何特定物件獨立開來。靜態成員函式即使在類物件不存在的情況下也能被呼叫,靜態函式只要使用類名加範圍解析運算子 :: 就可以訪問。
靜態成員函式只能訪問靜態成員資料、其他靜態成員函式和類外部的其他函式。
靜態成員函式有一個類範圍,他們不能訪問類的 this 指標。您可以使用靜態成員函式來判斷類的某些物件是否已被建立。
靜態成員函式與普通成員函式的區別:
- 靜態成員函式沒有 this 指標,只能訪問靜態成員(包括靜態成員變數和靜態成員函式)。
- 普通成員函式有 this 指標,可以訪問類中的任意成員;而靜態成員函式沒有 this 指標。
下面的例項有助於更好地理解靜態成員函式的概念:
#include <iostream>
using namespace std;
class Box
{
public:
static int objectCount;
// 建構函式定義
Box(double l=2.0, double b=2.0, double h=2.0)
{
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
// 每次建立物件時增加 1
objectCount++;
}
double Volume()
{
return length * breadth * height;
}
static int getCount()
{
return objectCount;
}
private:
double length; // 長度
double breadth; // 寬度
double height; // 高度
};
// 初始化類 Box 的靜態成員
int Box::objectCount = 0;
int main(void)
{
// 在建立物件之前輸出物件的總數
cout << "Inital Stage Count: " << Box::getCount() << endl;
Box Box1(3.3, 1.2, 1.5); // 宣告 box1
Box Box2(8.5, 6.0, 2.0); // 宣告 box2
// 在建立物件之後輸出物件的總數
cout << "Final Stage Count: " << Box::getCount() << endl;
return 0;
}
當上面的程式碼被編譯和執行時,它會產生下列結果:
Inital Stage Count: 0
Constructor called.
Constructor called.
Final Stage Count: 2