January 8, 2021

Coding11 - C++ Primer Part2

This is a C++ note for my own review and study.

十一:C++字符串

字符串是字符的集合。C++語言中通常使用兩種類型的字符串:

C-strings

在C語言中,字符集合以數組的形式存儲,C++也支持這樣形式,所以稱為C-strings。

C-strings是以char空字符結尾類型的數組,即\0(空字符的ASCII值為0)。

如何定義一個C-strings

1
char str [] = " C ++";

在上面的代碼中str是一個字符串,包含了4個字符,C++有3個字符,空字符\0會自動添加到字符串末尾。

定義字符串的替代方法

1
2
3
char str [4] = " C ++";
char str [] = {'C', '+', '+', '\ 0'};
char str [4] = {'C', '+', '+', '\ 0'};

像數組一樣,我們不必為strings分配所有的空間:

1
char str [100] = " C ++";
使用C++ strings讀取單詞

C++顯示用戶輸入的字符串:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iosteam>
using namespace std;

int main()
{
char str[100];

cout << "Enter a string: ";
cin >> str;
cout << "You entered: " << str << endl;

cout << "\nEnter another string: ";
cin >> str;
cout << "You entered: " << sr <, endl;
return 0;
}

/* OUTPUT
Enter a string: C++
You entered: C++

Enter another string: Programming is fun.
You entered: Programming
*/

在第二個結果中只會顯示“Programming”,是因為提取運算符號>>與scanf()一樣,認為空格是終止字符。

示例二:C++ strings讀取一行文本

C++讀取並顯示用戶輸入的整行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;

int main()
{
char str[100];
cout << "Enter a string: ";
cin.get(str, 100);

cout << "You entered: " << str << endl;
return 0;
}

/* OUTPUT
Enter a string: Programming is fun.
You entered: Programming is fun.
*/

為了讀取包含空格的文本,cin.get函數可以使用,它帶有2個參數。

第一個參數是字符串的名稱(字符串第一個元素的地址),第二個參數是數組的最大size。

Strings對象

在C++中,你還可以創建一個用於保存字符串的字符串對象。

與char數組不同,字符串對象沒有固定的長度,可以按需求進行擴展。

示例三:使用字符串數據類型的C++ strings
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;

int main()
{
// Declaring a string object
string str;
cout << "Enter a string: ";
getline(cin, str);

cout << "You entered: " << str << endl;
return 0;
}

/* OUTPUT
Enter a string: Programming is fun.
You entered: Programming is fun.
*/

我們可以通過輸入文本行的getline()方法來控制輸入,getline()函數將輸入流cin作為第一個參數。

將strings傳遞給函數

字符串也可以通過類似數組的方式傳遞給函數。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
using namespace std;

void display(char *);
void display(string);

int main()
{
string str1;
char str[100];

cout << "Enter a string: ";
getline(cin, str1);

cout << "Enter another string: ";
cin.get(str, 100, '\n');

display(str1);
dislay(str);
return 0;
}

void display(char s[])
{
cout << "Entered char array is: " << s << endl;
}
void display(string s)
{
cout << "Entered string is: " << s << endl;
}

/* OUTPUT
Enter a string: Programming is fun.
Enter another string: Really?
Entered string is: Programming is fun.
Entered char array is: Really?
*/

第一個函數display()將char數組作為參數傳遞,第二個函數display()將string作為參數傳遞。


十二:C++結構

結構是一個單一名稱下不同數據類型的變量的集合,例如關於某人的信息可以是不同的變量組成:name1, citNo1, salary1, name2, citNo2, salary2

這些變量看起來會有些混亂,所以最好的方法是通過一個person來將信息整理起來,這樣代碼也更加簡潔,易讀和高效。而這樣的一個person就是一個結構。

如何在C++中聲明結構?

struct關鍵詞是定義結構的方法。在{}內會包括多個變量:

1
2
3
4
5
6
struct Person
{
char name[50];
int age;
float salary;
};

這就是一個結構person定義含有了三個元素:name, age, and salary

結構被創建時,不會被分配任何內存。

結構定義僅指定結構變量在定義時具有的屬性。

NOTE

需要再結尾以 ‘;’ 結束聲明

如何定義結構變量?

當你聲明了結構person之後,你可以定義一個結構變量,例如:

1
Person bill;

一個結構變量bill被定義了,是類型結構Person

當結構變量被定義了,所需的內存才會被編譯器分配。考慮到你使用32-bit或64-bit的系統,float是4字節,int是4字節,char是1字節。所以我們這個bill佔據58字節。

如何訪問結構的元素?

我們可以可以通過dot(.)方法,如下:

1
bill.age = 50;
C++結構示例

在C++中將數據分配給結構變量並顯示他們:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
using namespace std;

struct Person
{
char name[50];
int age;
float salary;
};

int main()
{
Person p1;
cout << "Enter Full name: ";
cin.get(p1.name, 50);
cout << "Enter age: ";
cin >> p1.age;
cout << "Enter salary: ";
cin >> p1.salary;

cout << "\nDisplaying Information." << endl;
cout << "Name: " << p1.name << endl;
cout << "Age: " << p1.age << endl;
cout << "Salary: " << p1.salary;

return 0;
}


/* OUTPUT
Enter Full name: Magdalena Dankova
Enter age: 27
Enter salary: 1024.4

Displaying Information.
Name: Magdalena Dankova
Age: 27
Salary: 1024.4
*/

十三:C++結構與函數

將結構傳遞給C++中的函數,我們可以通過下面幾個例子來了解:

示例一:C++結構與函數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
using namespace std;

struct Person
{
char name[50];
int age;
float salary;
};

void displayData(Person); // Function declaration

int main()
{
Person p;

cout << "Enter Full name: ";
cin.get(p.name, 50);
cout << "Enter age: ";
cin >> p.age;
cout << "Enter salary: ";
cin >> p.salary;

// Function call with structure variable as an argument
displayData(p);

return 0;
}

void displayData(Person p)
{
cout << "\nDislaying Information." << endl;
cout << "Name: " << p.name << endl;
cout << "Age: " << p.age << endl;
cout << "Salary: " << p.salary;
}

/* OUTPUT
Enter Full name: Bill Jobs
Enter age: 55
Enter salary: 34233.4

Displaying Information.
Name: Bill Jobs
Age: 55
Salary: 34233.4
*/

在這個程序中,用戶被要求輸入nameagesalary來存儲在結構p中。

然後結構p把數據傳遞給了函數displayData(p)

從C++函數返回結構
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
using namespace std;

struct Person
{
char name[50];
int age;
float salary;
};

Person getData(Person);
void displayData(Person);

int main()
{
Person p;

p = getData(p);
displayData(p);
return 0;
}

Person getData(Person p)
{
cout << "Enter Full name: ";
cin.get(p.name, 50);

cout << "Enter age: ";
cin >> p.age;

cout << "Enter salary: ";
cin >> p.salary;

return p;
}

void displayData(Person p)
{
cout << "\nDislaying Information." << endl;
cout << "Name: " << p.name << endl;
cout << "Age: " << p.age << endl;
cout << "Salary: " << p.salary;
}


// 在這裡,首先聲明結構Person,再通過 getData()來定義結構,最後通過displayData()打印數據。

十四:C++結構指針

一個指針變量不僅可以通過本地類型(int, float, doubleetc.)創建,也可以通過用戶定義的類型創建,例如結構。

下面是一個你可以創建結構指針的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iosteram>
using namespace std;

struct temp
{
int i;
float f;
};

int main()
{
temp *ptr;
return 0;
}

這個程序船艦了一個結構tempptr指針。

結構指針示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
using namespace std;

struct Distance
{
int feet;
float inch;
};

int main()
{
Distance *ptr, d;

ptr = &d;

cout << "Enter feet: ";
cin >> (*ptr).feet;
cout << "Enter inch: ";
cin >> (*ptr).inch;

cout << "Displaying information." << endl;
cout << "Distance = " << (*ptr).feet << " feet " << (*ptr).inch << " inches";

return 0;
}

/* OUTPUT
Enter feet: 4
Enter inch: 3.5
Displaying information.
Distance = 4 feet 3.5 inches
*/

在這個程序中,指針變量ptr和類型函數Distance的普通變量d被定義。

變量d的地址被存儲在指針變量,ptr指向變量d。然後變量d的函數元素可以被指針訪問了。

NOTE

因為指針ptr指向了變量d,所以是(*ptr).inchd.inch是相同的,(*ptr).feetd.feet也是相同的。

使用指針訪問函數元素通常還可以被 “->” 代替:

1
2
ptr->feet is same as (*ptr).feet
ptr->inch is same as (*ptr).inch

十五:C++枚舉(Enumeration)

枚舉是用戶定義的數據類型,由整數常量組成,定義枚舉需要用到關鍵字enum。

1
enum season { spring, summer, autumn, winter };

這裡,枚舉的名稱是season, spring,summerwinter是值。

默認的情況下,spring是0,summer是1,依次類推。你可以改變枚舉默認的值。

1
2
3
4
5
6
7
enum season
{
spring = 0;
summer = 4;
autumn = 8;
winter = 12
};
枚舉類型聲明

這是創建枚舉變量的方法:

1
2
3
4
enum boolean { false, true };

// inside function
enum boolean check;

這樣,一個變量check的類型enum boolean被創建了。

這是另一個聲明check變量的語法:

1
2
3
4
enum boolean
{
false, true
} check;
示例一:枚舉類型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;
enum week { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
int main()
{
week today;
today = Wednesday;
cout << "Day" << today+1;
return 0;
}

/* OUTPUT
4
*/
示例二:改變枚舉的默認值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;

enum seasons { spring = 34, summer = 4, autumn = 9, winter = 32};

int main()
{
seasons s;

s = summer;
cout << "Summer = "<< s << endl;

return 0;
}

/* OUTPUT
4
*/
為什麼C++中會使用枚舉?

枚舉變量只會從許多可能值中獲取一個(看不懂):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
3include <iostream>
using namespace std;

enum suit
{
club = 0,
diamonds = 10,
hearts = 20,
spades = 3
} card;

int main()
{
card = club;
cout << "Size of enum variable " << sizeof(card) << "bytes.";
return 0;
}

/* OUTPUT
Size of enum variable 4 bytes.
*/

因為int的大小為4 bytes。

枚舉可以成為好的work with flags。

我們也可以通過結構完成相同的任務,但是枚舉可以提高效率和靈活性。

如何將enum用於flags?

看看下面這個例子:

1
2
3
4
5
6
enum designFlags 
{
ITALICS = 1,
BOLD = 2,
UNDERLINE = 4
} button;

就像你在設計Windows應用的button一樣,你可以設置ITALICSBOLDUNDERLINE來處理文本。

為什麼他們都是2的積分常數?

1
2
3
4
5
// In binary

ITALICS = 00000001
BOLD = 00000010
UNDERLINE = 00000100

因為不會重複,所以我們可以一次選擇多個flags:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
using namespac std;

enum designFlags
{
BOLD = 1,
ITALICS = 2,
UNDERLINE = 4,
};

int main()
{
int myDesign = BOLD | UNDERLINE;
// 00000001
// | 00000100
// ___________
// 00000101

cout << myDesign;

return
}

/* OUTPUT
5
*/

所以當輸出為5的時候,你可以知道使用了粗體和下劃線。

你也可以添加flags到需求裡。

1
2
3
if (myDesign & ITALICS) {
// code for italics
}

我們在設計中添加了斜體。只有洩題代碼寫在了if語句中。

你可能不需要枚舉就可以在C++中完成幾乎所有的任務。但是他們在某些情況下非常方便,這也是好的程序員和優秀的程序員的不同之處。


十六:C++類與對象

假設我們需要存儲矩形房間的長度,寬度,高度,並計算面積和體積。

為了處理該任務,我們可以創建三個變量:lengh,height,breadth以及函數calculateArea()calculateVolume()

但是在C++中,除了創建單獨的變量和函數,我們還可以將相關的數據和函數包裝在一個地方(通過創建對象)。這種編程範例為面向對象編程。

但是在創建對象,並在C++中使用它之前,我們首先需要了解類。

C++ Class

Class是對象的藍圖,我們可以把Class視為是房子的草圖。它包括地板,門,窗戶等詳細信息,基於這些,我們創建了房子,房子就是對象。

在C++中,使用關鍵字定義一個Class,Class後跟著類的名稱,類的主體在大括號內定義,並在末尾以分號終止。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class className 
{
// some data
// some functions
};

// example

class Room {
public:
double length;
double breadth;
double height;

double calculateArea()
{
return length * breadth;
}
double calculateVolume()
{
return length * breadth * height;
}
};

在這裡我們定義了一個名為Room的類,在類中聲明的變量length, breadthheight被稱為數據成員。函數calculateArea()calculateVolume()被稱為成員函數

C++對象

定義類時,僅定義對象的規範,沒有分配內存和存儲空間。

要使用該類中定義的數據和訪問功能,我們需要創建對象。

在C++中定義對象的語法
1
className objectVariableName;

我們可以創建Room類的對象,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
// sample function
void sampleFunction()
{
// create objects
Room room1, room2;
}

int main()
{
// create objects
Room room3, room4;
}

在這裡,兩個對象room1room2在函數sampleFunction()中創建,room3room4在函數main()中創建。

我們可以在程序的任何函數中創建類對象,也可以在類本身或其他類中創建類的對象。

C++訪問數組成員和成員函數

我們可以使用.運算符訪問類的數據成員和成員函數,例如:

1
room2.calculateArea()

這會調用類room2的函數calculateArea()

同樣也可以使用下面的方法來訪問數據成員:

1
room1.length = 5.5;

在這樣的情況下,將room1的長度變量設置為5.5。

示例一:C++編程中的對象和類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// Program to illustrate the working of 
// bojects and class in C++ Programming

#include <iostream>
using namespace std;

// create a class
class Room {

public:
double length;
double breadth;
double height;

double calculateArea()
{
return length * breadth;
}

double calculateVolume()
{
return length * breadth * height;
}
};

int main()
{

// create object of Room class
Room room1;

room1. length = 42.5;
room1. breadth = 30.8;
room1. height = 19.2;

// calculate and display the area and volume of the room
cout << "Area of Room = " << room1.calculateArea() << endl;
cout << "Volume of Room = " << room1.calculateVolume() << endl;

return 0;
}

/* OUTPUT
Area of Room = 1309
Volume of Room = 25132.8
*/

在這個項目中,我們使用了類Room還有它的對象room1來計算房間的面積和體積。

main()中,我們設定了lengthbreadthheight的值:

1
2
3
room1.length = 42.5;
room1.breadth = 30.8;
room1.height = 19.2;

然後,我們調用函數calculateArea()calculateVolume()執行計算。

我們在程序中使用了關鍵詞public,這意味著成員是公開的,並且可以在程序中的任何位置來訪問。

根據我們的需求,我們還可以使用private關鍵詞來創建似有成員。例如:

1
2
3
4
5
6
7
8
9
class Test {
private:
int a;
void function1() {}

public:
int b;
void function2() {}
}
示例二:在C++類中使用public和private
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// Program to illustrate the working of
// public and private in C++ Class

#include <iostream>
using namespace std;

class Room {

private:
double length;
double breadth;
double height;

public:

// function to initialize private variables
void getData(double len, double brth, double hgt)
{
length = len;
breadth = brth;
height = hgt;
}

double calculateArea()
{
return length * breadth;
}

double calculateVolume()
{
return length * breadth * height;
}
};

int main()
{
// create object of Room class
Room room1;

// pass the values of private variables as arguments
room1.getData(42.5, 30.8 ,19.2);

cout << "Area of Room = " << room1. calculateArea() << endl;
cout << "Volume of Room = " << room1. calculateVolume() << endl;

return 0;
}

/* OUTPUT
Area of Room = 1309
Volume of Room = 25132.8
*/

這個例子與上一個示例相同,只是變量變成了私有的。

由於變量變成了私有的,我們無法在main()中訪問它們,因此下面的代碼會無效:

1
2
3
4
// invalid code
obj.length = 42.5;
obj.breadth = 30.8;
obj.height = 19.2;

相反的,我們可以使用公共函數getData()通過函數的參數初始化私有變量。


十七:C++構造函數

構造函數是成員函數的一個特殊類型,在創建對象時會自動調用,構造函數的名稱與類的名稱相同,並且沒有返回類型。例如:

1
2
3
4
5
6
7
8
class Wall {
public:

// create a constructor
Wall(){
// code
}
};

在這裡,函數Wall()是類Wall的構造函數,請注意,構造函數:

1.與類名稱相同

2.沒有返回類型,並且是public

沒有參數的構造函數稱為默認構造函數。在上面的示例中,Wall()是默認的構造函數。

示例一:C++默認構造函數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// C++ program to demonstrate the use of default constructor

#include <iostream>
using namespace std;

// declare a class
class Wall {

private:
double length;

public:
// create a constructor
Wall() {

// initialize private variables
length = 5.5;

cout << "Creating a wall." << endl;
cout << "Length = " << length << endl;
}
};

int main() {

// creat an object
Wall wall1;

return 0;
}

/* OUTPUT
Creating a wall
Length = 5.5
*/

在這裡,當Wall1被創建後,Wall()調用為構造函數。

如果我們沒有在類中定義構造函數,則C++編譯器會自動創建一個空代碼且無參數的默認構造函數。

C++參數化構造函數;在C++中,帶有參數的構造函數稱為參數化構造函數。這是初始化成員數據的首選方法。

示例二:C++參數化構造函數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// C++ program to calculate the area of a wall

#include <iostream>
using namespace std;

// declare a class
class Wall {
private:
double length;
double height;

public:
// create parameterized constructor
Wall(double len, double hgt) {
// initialize private variables
length = len;
height = hgt;
}

double calculateArea()
{
return length * height;
}
};

int main() {
//create object and initialize data menbers
Wall wall1(10.5, 8.6);
Wall wall2(8.5, 6.3);

cout << "Area of Wall 1: " << wall1.calculateArea() << endl;
cout << "Area of Wall 2: " << wall2.calculateArea() << endl;

return 0;
}

/* OUTPUT
Area of Wall 1: 90.3
Area of Wall 2: 53.55
*/

在這裡,我們創建了一個Wall()帶有兩個參數的參數化構造函數:double lendouble hgt。在這參數中包括了用於初始化成員變量的lengthheight

當創建Room類對象時,我們將成員變量的值作為參數傳遞。代碼塊是:

1
2
Wall wall1(10.5, 8.6);
Wall wall2(8.5, 6.3);

通過初試後成員變量,我們現在可以使用calculateArea()函數計算面積。

C++複製構造函數,C++中的複製構造函數用於將一個對象的數據複製到另一個對象。

示例三:C++複製構造函數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iosteam>
using namespace std;

//declare a class
class Wall {
private:
double length;
double height;

public:

// parameterized coustructor
Wall(double len, double hgt)
{
// initialize private variables
length = len;
height = hgt;
}

// copy constructor with a Wall object as parameter
Wall(Wall &obj) {
// initialize private variables
length = obj.length;
height = obj.height;
}
double calculateArea() {
return length * height;
}
};

int main() {

// create an boject of Wall class
Wall wall1(10.5, 8.6);

// print area of wall1
cout << "Area of Room 1: " << wall1.calculateArea() << endl;

// copy contents of room1 to another object room2
Wall wall2 = wall1;

// print area of wall2
cout << "Area of Room 2: " << wall2.calculateArea() << endl;

return 0;
}

/* OUTPUT
Area of Room 1: 90.3
Area of Room 2: 90.3
*/

在這個程序中,我們使用了構造函數Wall,把一個對象的內容複製到另一個對象,複製構造函數的代碼為:

1
2
3
4
Room(Room &obj) {
length = obj.length;
height = obj.height;
}

構造函數的參數具有Wall類對象的地址。

然後,我們將第一個對象的變量值分配給第二個對象的相應變量。這就是複製對象內容的方式。

構造函數主要用於初始化對象,創建對象時,他們還用於運行默認代碼。


十八:通過C++函數傳遞和返回對象

在C++編程中,我們還可以通過與傳遞常規參數類似的方法來將對象傳遞給函數。

示例一:C++將對象傳遞給函數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// C++ program to calculate the average marks of two students

#include <iostream>
using namespace std;

class Student {

public:
double marks;

// constructor to initialize marks
Student(double m) {
marks = m;
}
};

// function that has objects as parameters
void calculateAverage(Student s1, Student s2) {

// calculate the average of marks of s1 and s2
double average = (s1.marks + s2.marks) / 2;

cout << "Average Marks = " << average << endl;

}

int main() {
Student student1(88.0), student2(56.0);

// pass the objects as arguments
calculateAverage(student1, student2);

return 0;
}

/* OUTPUT
Average Marks = 72
*/

在這裡,我們傳遞了兩個Student對象student1student2作為函數calculateAverage()的參數。

示例二:C++從函數返回對象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
using namespace stdl

class Student {
public:
double marks1, marks2;
};

// function that returns object of Student
Student createStudent() {
Student student;

// Initialize member variables of Student
student.marks1 = 96.5;
student.marks2 = 75.0;

// print member variables of Student
cout << "Marks 1 = " << student.marks1 << endl;
cout << "Marks 2 = " << student.marks2 << endl;

return student;
}

int main() {
Student student1;

// Call function
student1 = createStudent();

return 0;
}

/* OUTPUT
Marks 1 = 96.5
Marks 2 = 75
*/

在程序中,我們創建了一個createStudent()函數,返回類Student的對象。

我們的createStudent()main()方法中調用了。

1
2
// Call function
student1 = createStudent();

我們將createStudent()方法返回的對象存儲在了student1中。


十九:C++運算符重載

在C++中,我們可以更改運算符對用戶定義類型的工作方式(如對象和結構)。這稱為運算符重載。例如:

假設我們創建了三個對象c1c2result來自一個Complex代表複數的類。

由於運算符重載允許我們更改運算符的工作方式,你次我們可以重新定義運算符的工作方式,使用+來添加運算符的複數。

1
result = c1 + c2;

而不是像:

1
result = c1.addNumbers(c2);

這樣我們的代碼直觀易懂。

我們不能用運算符重載基本的數據類型,例如intfloatchar等。

C++運算符重載的語法

為了使運算符重載,我們使用了一個特殊的operator函數。

1
2
3
4
5
6
7
8
class className {
... .. ...
public:
returnType operator symbol (arguments) {
... .. ...
}
... .. ...
};

returnType使函數的返回類型,運算符是關鍵字,symbol是我們要重載的運算符,例如+-<++等等。

一元運算符中的運算符重載,一元運算符只能對一個操作數進行運算。增量運算符++和減量運算符--

示例一:++運算符重載
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Oerload ++ when used as prefix

#include <iostream>
using namespace std;

class Count {
private:
int value;

public:

// Constructor to initialize count to 5
Count() : value(5) {}

// Overload ++ when used as prefix
void operator ++ () {
++value;
}

void display() {
cout << "Count: " << value << endl;
}
};

int main() {
Count count1;

// Call the "void operator ++ ()" function
++count1;

count1.display();
return 0;
}

/* OUTPUT
Count: 6
*/

當我們重載運算符時,我們可以使用任何我們喜歡的方式,例如++可以增加100;但是這樣會讓我們的代碼混亂難以理解,我們的工作是以一致且直觀的方式正確使用運算符重載。

上面的示例僅在++作為前綴時才有用,為了使++變為後綴,我們可以如下:

1
2
3
void operator ++ (int) {
// code
}

這是用於將一元運算符用作後綴的語法,他不是一個函數參數。

示例二:++運算符重載
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// Overload ++ when used as prefix and postfix

#include <iostream>
using namespace std;

class Count {
private:
int value;

public:

// Constructor to initialize count to 5
Count() : value(5) {}

// Overload ++ when used as prefix
void operator ++ () {
++value;
}

// Overload ++ when used as postfix
void operator ++ (int) {
++value;
}

void display() {
cout << "Count: " << value << endl;
}
};

int main() {
Count count1;

// Call the "void operator ++ (int)" function
count1++;
count1.display();

// Call teh "void operator ++ ()" function
++ count1;

count1.display();
return 0;
}

/* OUTPUT
Count: 6
Count: 7
*/

我們實現了++前綴和後綴。但是如果我們嘗試以下操作,則無效:

1
2
3
4
Count count1, result;

// Error
result = ++count1;

這是因為運算符返回類型為void。我們可以通過Count將運算符作為返回類型來解決此問題。

1
2
3
4
5
6
7
8
9
10
11
// return Count when ++ used as prefix

Count operator ++ () {
// code
}

// return Count when ++ used as postfix

Count operator ++ (int) {
// code
}
示例三:從運算符函數返回值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
using namespace std;

class Count {
private:
int value;

public:
// Constructor to initialize count to 5
Count() : value(5) {}

// Overload ++ when used as prefix
Count operator ++ () {
Count temp;

// Here, value is the value attribute of teh calling object
temp.value = ++value;

return temp;
}

// Overload ++ when used as postfix
Count operator ++ (int) {
Count temp;

// Here, value is teh value attribute of teh calling object
temp.value = ++value;

return temp;
}

void display() {
cout << "Count: " << value <, endl;
}
};

int main() {
Count count1, result;

// Call teh "Count operator ++ ()" function
result = ++count1;
result.display();

return 0;
}

/* OUTPUT
Count: 6
Count: 7
*/

在這裡,我們使用以下代碼進行前綴運算符重載:

1
2
3
4
5
6
7
8
9
// Overload ++ when used as prefix
Count operator ++ () {
Count temp;

// Here, value is teh value attribute of teh calling object
temp.value = ++value;

return temp;
}

我們創建了一個對象temp並將其值返回給operator函數。

1
temp.value = ++value;

The variable value belongs to the count1 object in main() because count1 is calling the function, while temp.value belongs to the temp object.

二元運算符中的運算符重載,二進制運算符處理兩個數:

1
resulut = num + 9;

這裡,+是一個操作二進制運算符num9

當我們通過代碼重載用於用戶自定義類型的二進制運算符時:

1
obj3 = obj1 + obj2;

使用obj1obj2作為參數傳遞給函數。

C++二進制運算符重載
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// C++ program to overload the binary operator +
// This program adds two complex numbers

#include <iostream>
using namespace std;

class Complex {
private:
float real;
float imag;

public:
// Constructor to initialize real and imag to 0
Complex() : real(0), imag(0) {}

void input() {
cout << "Enter real and imaginary parts repectively:";
cin >> real;
cin >> imag;
}

// Overload the + operator
Complex operator + (const Complex& obj) {
Complex temp;
temp.real = real + obj.real;
temp.imag = imag + obj.imag;
return temp;
}

void output() {
if(imag < 0)
cout << "Output Complex number: " << real << imag << "i";
else
cout << "Output Complex number: " << real << "+" << imag << "i";
}
};

int main() {
Complex complex1, complex2, result;

cout << "Enter first complex number:\n";
complex1.input();

cout << "Enter second complex number;\n";
complex2.input();

// complex1 calls the operator function
// complex2 is passed as an argument to the function
result = complex1 + complex2;
result.output();

return 0;
}

/* OUTPUT
Enter first complex number:
Enter real and imaginary parts respectively: 9 5
Enter second complex number:
Enter real and imaginary parts respectively: 7 6
Output Complex number: 16+11i
*/

在這個程序中,字符串重載函數為:

1
2
3
Complex operator + (const Complex& obj) {
// code
}

除此之外,我們也可以編寫如下函數:

1
2
3
Complex operator + (Complex obj) {
// code
}

使用&提升代碼效率,通過引用Complex2對象,而不需要再運算符函數中創建重複的對象。

使用const是一個好習慣,可以阻止operator函數修改complex2

C++運算符重載中的注意項

1.兩個運算符=&已經在C++中被默認重載,我們不需要創建運算符。

2.運算符重載不能更改運算符的優先級和關聯性,如果要調整計算順序,需要使用括號。

3.C++中有4個不能重載的運算符,它們是:

​ a.::(scope resolution)

​ b..(member selection)

​ c..*(member selection through pointer to function)

​ d.?:(ternary operator)


二十:C++指針

在C++中,指針是存儲其他變量的內存地址的變量。

如果我們有一個變量var&var可以給我提供它在內存中的地址:

示例一:在C++中打印變量地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
using namespace std;

int main()
{
// declare variables
int var1 = 3;
int var2 = 24;
int var3 = 17;

// print address of var1
cout << "Address of var1: " << &var1 << endl;

// print address of var2
cout << "Address of var2: " << &var2 << endl;

// print address of var3
cout << "Address of var3: " << &var3 << endl;
}

/* OUTPUT
Address of var1: 0x7fff5fbff8ac
Address of var2: 0x7fff5fbff8a8
Address of var3: 0x7fff5fbff8a4
*/

在這裡0x開頭表示是十六進制的地址。

運行時的結果可能是不同的,按需分配。

C++指針

如上所述,指針存儲的是地址而不是值。

聲明指針的方法:

1
int *pointVar

在這裡,我們聲明了一個指針 int類型的pointVar 指針。

我們也可以通過下面的方式聲明指針:

1
int* pointVar

我們還可以再舉一個聲明指針的例子:

1
int* ponitVar, p;

在這裡我們聲明了一個指針pointVar和一個普通變量p

給指針分配地址

下面是我們給指針分配地址的示例:

1
2
3
4
5
int* pointVar, var;
var = 5;

// assign address of var to pointVar pointer
pointVar = &var;

在這裡,我們首先將5分配給了變量varvar的地址被配給指針pointVar

使用指針從地址獲取值

為了獲得指針所指向的值,我們使用*符號,例如:

1
2
3
4
5
6
7
8
9
10
11
12
int* pointVar, var;
var = 5;

// assign address of var to pointVar
pointVar = &var;

// accesss value pointer by pointVar
cout << *pointVar << endl;

/* OUTPUT
5
*/

在上面的代碼中,var的地址被分配給了pointVar,我們已經使用了*pointVar來獲取存儲在地址中的值。

*與指針使用時,它表示引用操作,對指針操作,並給出指針中存儲地址指向的值,即:*pointVar = var

在C++中,pointVar*pointVar不同,我們不能這樣做: *pointVar = &var;

示例二:C++指針工作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
using namespcae std;
int main()
{
int var = 5;

//declare pointer variable
int* pointVar;

// store address of var
pointVar = &var;

// print value of var
cout << "var = " << var << endl;

// print address of var
cout << "Address of var(&var) = " << &var << endl << endl;

// print pointer pointVar
cout << "pointVar = " << pointVar << endl;

// print the content of the address pointVar points to
cout << "Content of teh address pointed to by pointVar (*pointVar) = " << *pointVar << endl;

return 0;
}

/* OUTPUT
var = 5
Address of var (&var) = 0x61ff08

pointVar = 0x61ff08
Content of the address pointed to by pointVar (*pointVar) = 5

*/

改變指針指向的值,如果pointVar指向var的地址,我們可以通過*pointVar改變var的數值。舉例:

1
2
3
4
5
6
7
8
9
10
int var = 5;
int* pointVar;

// assign address of var
pointVar = &var;

// change value at address pointVar
*pointVar = 1;

cout << var << endl; // Output: 1

這裡,pointVar&var 有相同的地址,所以當*pointVar被改變的時候,var可以被改變。

示例三:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
using namespace std;
int main()
{
int var = 5;
int* pointVar;

// store address of var
pointVar = &var;

// print var
cout << "var = " << var << endl;

// print *pointVar
cout << "*pointVar = " << *pointVar << endl << endl;

cout << "Changing value of var to 7: " << endl;

// change value of var to 7
var = 7;

// print var
cout << "var = " << var << endl;

// print *pointVar
cout << "*pointVar = " << *pointVar << endl << endl;

cout << "Changing value *pointVar to 16:" << endl;

// change value of var to 16
*pointVar = 16;

// print var
cout << "var = " << var << endl;

// print *pointVar
cout << "*pointVar = " << *pointVar << endl;

return 0;
}

/* OUTPUT
var = 5
*pointVar = 5

Changing value of var to 7:
var = 7
*pointVar = 7

Changing value of *pointVar to 16:
var = 16
*pointVar = 16
*/
使用指針時的常見錯誤

假設,我們想要指針varPoint指向var的地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int var, *varPoint;

// Wrong!
// varPoint is an address but var is not
varPoint = var;

// Wrong!
// &var is an address
// *varPoint is the value stored in &var
*varPoint = &var;

// Correct!
// varPoint is an address and so is &var
varPoint = &var;

// Correct!
// both *varPoint and var are values
*varPoint = var;

Recommended Readings:

About this Post

This post is written by Siqi Shu, licensed under CC BY-NC 4.0.