January 15, 2021

Coding12 - C++ Primer Part3

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

二十一:C++指針和數組

在C++中,指針是保存其他變量地址的變量。指針不僅可以存儲單個變量的地址,還可以存儲數組的單元格地址。

參考以下示例:

1
2
3
4
5
6
int *ptr;
int arr[5];

// store the address of the first
// element of arr in ptr
ptr = arr;

這裡,ptr是一個指針變量,而arr是一個int類型的數組,代碼ptr = arr;將數組的第一個元素地址存儲在了變量ptr中。

1
2
3
int *ptr;
int arr[5];
ptr = &arr[0];

而我們需要獲取其他元素的地址,可以使用&arr[1]&arr[2]&arr[3]&arr[4]

指向每個數組元素

假設我們需要使用相同的指針指向數組的第四個元素ptr

在這裡,如果ptr指向第一個元素,那麼ptr + 3則指向第四個元素。舉例:

1
2
3
4
5
6
7
8
int *ptr;
int arr[5];
ptr = arr;

ptr + 1 is equivalent to &arr[1];
ptr + 2 is equivalent to &arr[2];
ptr + 3 is equivalent to &arr[3];
ptr + 4 is equivalent to &arr[4];

同樣,我們也可以說使用單個指針訪問元素。舉例:

1
2
3
4
5
6
// use dereference operator
*ptr == arr[0];
*(ptr + 1) is equivalent to arr[1];
*(ptr + 2) is equivalent to arr[2];
*(ptr + 3) is equivalent to arr[3];
*(ptr + 4) is equivalent to arr[4];

假設我們已經初始化,ptr = &arr[2],然後:

1
2
3
4
ptr - 2 is equivalent to &arr[0];
ptr - 1 is equivalent to &arr[1];
ptr + 1 is equivalent to &arr[3];
ptr + 2 is equivalent to &arr[4];

注意,地址ptrptr + 1相差4個字節,因為int的大小為4個字節。

同樣,如果指針ptr指向char類型數據,ptrptr + 1差1個字節,因為字符的大小是一個字節。

示例一: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
// C++ Program to display address of each element of an array

#include <iostream>
using namepsace std;
int main()
{
float arr[3];

// declare pointer variable
float *ptr;

cout << "Displaying address using arrays: " << endl;

// use for loop to print addresses of all array elements
for (int i = 0; i < 3; ++i)
{
cout << "&arr[" << i << "] = " << &arr[i] << endl;
}

// ptr = &arr[0]
ptr = arr;

cout << "\nDisplaying address using pointers: " << endl;

// use for loop to print addresses of all array elements
// using pointer notation
for (int i = 0; i < 3; ++i)
{
cout << "ptr + " << i << " = " << ptr + i << endl;
}

return 0;
}


/* OUTPUT
Displaying address using arrays:
&arr[0] = 0x61fef0
&arr[1] = 0x61fef4
&arr[2] = 0x61fef8

Displaying address using pointers:
ptr + 0 = 0x61fef0
ptr + 1 = 0x61fef4
ptr + 2 = 0x61fef8
*/

在這個程序中,我們打印了數組元素地址兩次,第一次沒有使用指針變量,第二次使用指針變量ptr,以及ptr + i等於arr[0+i]

在大多數情況下,數組名稱會定義為指針名,這也是為什麼我們可以使用指針訪問數組元素。但是我們應該記住,指針和數組並不相同,在某些情況下,數組名稱不會變為指針。To learn more, visit: When does array name doesn’t decay into a pointer?

示例二:數字名稱用作指針
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
// C++ Program to insert and display data entered by using pointer notation.

#include <iostream>
using namespace std;

int main()
{
float arr[5];

// Insert data using pointer notation
cout << "Enter 5 numbers: ";
for (int i = 0; i < 5; ++i)
{

// store input number in arr[i]
cin >> *(arr + i);
}

// Display data using pointer notation
cout << "Displaying data: " << endl;
for (int i = 0; i < 5; ++i)
{

// display value of arr[i]
cout << *(arr + i) << endl;
}

return 0;
}

/* OUTPUT
Enter 5 numbers: 2.5
3.5
4.5
5
2
Displaying data:
2.5
3.5
4.5
5
2
*/

這裡,我們首先使用了指針符號來存儲數值。

1
cin >> *(arr + i);

這個代碼也等於如下:

1
cin >> arr[i]

同樣的使用for循環來顯示arr

1
cout << *(arr + i) << endl;

等效於:

1
cout << arr[i] << endl;

二十二: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
// function that takes value as parameter

void func1(int numVal)
{
// code
}

// function that takes reference as parameter
// notice the & before the parameter
void func2(int &numRef)
{
// code
}

int main()
{
int num = 5;

// pass by value
func1(num);

// pass by reference
func2(num);

return 0;
}

在函數void func2(int &numRef)中,我們正在使用變量的地址作為參數。

因此,當我們通過傳遞變量來調用func2()時,我們實際上是傳遞了num而不是數值5。

示例一:不帶指針的引用傳遞
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
#include <iostream>
using namespace std;

// function definition to swap values
void swap(int &n1, int &n2)
{
int temp;
temp = n1;
n1 = n2;
n2 = temp;
}

int main()
{

// initialize variables
int a = 1, b = 2;
cout << "Before swapping" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;

// call function to swap numbers
swap(a, b);

cout << "\nAfter swapping" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;

return 0;
}

/* OUTPUT
Before swapping
a = 1
b = 2

After swapping
a = 2
b = 1
*/

在這個程序中,我們傳遞了ab到函數swap()中,注意函數定義:

1
void swap(int &n1, int &n2);

這裡,我們使用了&來表示函數接受地址作為參數。

因此編譯器可以識別變量的引用被傳遞給函數參數,而不是實際值。

swap()函數中,函數參數n1n2指向與變量ab相同的值,實際發生了數值交換。

示例二:使用指針傳遞引用
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
#include <iostream>
using namespace std;

// function prototype with pointer as parameters
void swap(int*, int*);

int main()
{

// initialize variables
int a = 1, b = 2;

cout << "Before swapping" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;

// call function by passing variable addresses
swap(&a, &b);

cout << "\nAfter swapping" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
return 0;
}

// fucntion definition to swap numbers
void swap(int* n1, int* n2) {
int temp;
temp = *n1;
*n1 = *n2;
*n2 = temp;
}

/* OUTPUT
Before swapping
a = 1
b = 2

After swapping
a = 2
b = 1
*/

我們的輸出與上一個示例相同,注意這裡:

1
2
3
// &a is address of a 
// &b is address of b
swap(&a, &b);

變量的地址是在函數調用期間傳遞的,而不是在變量傳遞時傳遞的,由於傳遞的是地址而不是值,因此必須使用*來訪問存儲在該地址中的值。

1
2
3
temp = *n1;
*n1 = *n2;
*n2 = temp;

*n1*n2是地址中存儲的n1n2值。因為n1n2包括了ab的地址,任何改變*n1*n2的都會改變ab實際的值。

因此,當我們在main()函數中打印ab的函數,變量會被改變。


二十三:C++內存管理

C++允許我們在分配變量或數組的內存,這稱為動態內存分配。

在其他語言中(Java/Python)中,編譯器自動管理分配給變量內存,在C++中,我們不需要使用變量後,則需要手動釋放動態分配的內存。我們可以使用newdelete運算符動態分配和釋放內存。

C++運算符 new

new操作會給存儲器分配一個變量,例如:

1
2
3
4
5
6
7
8
9
// declare an int pointer
int* pointVar;

// dynamically allocate memory
// using the new keyword
pointVar = new int;

// assign value to allocated memory
*pointVar = 45;

在這裡,我們已使用newint動態分配了內存。

主義,我們已經使用了指針pointVar動態分配內存,因為new操作返回了存儲位置的地址。對於數組new運算符返回數組第一個元素的地址。

從上面的示例中,我們可以翻到使用了new運算符的語法是:

1
pointerVariable = new dataType;
C++運算符 delete

一旦不再需要使用動態聲明的變量,就可以釋放該變量佔用的內存。為此,我們需要使用delete運算符,它將內存返回操作系統,這稱為內存釋放(memory deallocation)

1
delete pointerVariable;

參考下面這段代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// declare an int pointer
int* pointVar

// dynamically allocate memory
// for an int variable
pointVar = new int;

// assign value to the variable memory
*pointVar = 45;

// print the value stored in memory
cout << *pointVar; // Output: 45

// deallocate the memory
delete memory;

在這裡,我們通過pointVar動態釋放了int的內存。在打印了pointVar之後,我們使用delete釋放了內存。

如果程序中new使用了太多不希望的內存,系統可能會崩潰,因為沒有可用的存儲空間了,我們可以通過delete方法來避免這樣的情況。

示例一: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
#include <iostream>
using namespace std;

int main() {
// declare an int pointer
int* pointInt;

// declare a float pointer
float* pointFloat;

// dynamically allocate memory
pointInt = new int;
pointFloat = new float;

// assigning value to the memory
*pointInt = 45;
*pointFloat = 45.45f;

cout << *pointInt << endl;
cout << *pointFloat << endl;

// deallocate the memory
delete pointInt, pointFloat;

return 0;
}

/* OUTPUT
45
45.45
*/

在這個程序中,我們動態釋放了兩個類型變量intfloat的內存。在分配數值和打印之後,我們使用delete來釋放內存。

1
delete pointInt, pointFloat;

動態內存釋放可以讓內存管理更有效。特別是對數組而言,我們只有運行時才能知道數組的大小。

示例二:C++數組的new&delete
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
// C++ Program to store GPA of n number of students and display it
// where n is the number of students entered by the user

#include <iostream>
#include <cstring>
using namespace std;

int main() {
int num;
cout << "Enter total number of students: ";
cin >> num;
float* ptr;

// memory allocation of num number of floats
ptr = new float[num];

cout << "Enter GPA of students." << endl;
for (int i = 0; i < num ++i) {
cout << "Student" << i + 1 << ": ";
cin >> *(ptr + i);
}

cout << "\nDisplaying GPA of students." << endl;
for (int i = 0; i < num; ++i) {
cout << "Student" << i + 1 << " :" << *(ptr + i) << endl;
}

// ptr memory is released
delete [] ptr;

return 0;
}

/* OUTPUT
Enter total number of students: 4
Enter GPA of students.
Student1: 3.6
Student2: 3.1
Student3: 3.9
Student4: 2.9

Displaying GPA of students.
Student1 :3.6
Student2 :3.1
Student3 :3.9
Student4 :2.9
*/

在這個程序中,我們詢問了用戶學生總數,並且存儲在了num變量中。

然後,我們通過new分配了float的內存。通過指針運算符將數據放入了數組。

在我們不需要數組之後,我們釋放了數組的內存,通過使用delete [] ptr

delete之後使用[],我們使用[]來表示時數組的釋放。

示例三:C++對象的new&delete
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
#include <iostream>
using namespace std;

class Student {
int age;

poblic:

// constructor initializes age to 12
Student() : age(12) {}

void getAge() {
cout << "Age = " << age << endl;
}
};

int main() {

// dynamically declare Student object
Student* ptr = new Student();

// call getAge() function
ptr->getAge();

// ptr memory is released
delete ptr;

return 0;
}

/* OUTPUT
Age = 12
*/

在這個程序中,我們創建了一個類Student,包含私有變量age。我們初始化age到構造函數Student()並使用函數getAge()打印值。

main()中,我們使用new創建Student對象,並使用指針ptr指向它的地址。創建對象後,構造函數Student()會把age初始化為12。然後我們getAge()會調用下面這個函數:

1
2
3
ptr->getAge();
// equal as below code:
(*ptr).getAge();

二十四:C++繼承

在C++中,繼承時面向對象編程的重要功能,它允許我們從現存的類中創建新的類。

派生類繼承了基類的功能,並且可以擁有自己的其他功能,例如:

1
2
3
4
5
6
7
8
class Animal {
// eat() function
// sleep() function
};

class Dog : public Animal {
// bark() function
};

Dog是從類Animal派生出來的,所以Animal的成員也可以在Dog中訪問。

在從Animal中繼承時,使用了關鍵字public

1
class Dog : public Animal {...};

我們還可以使用關鍵字privateprotected。我們將學習他們之間的差異,並在之後的教程中使用。

繼承是一種關係,僅在兩個類之間存在is-a關係是才可以使用,例如:

橘子是一種水果,外科醫生是醫生,🐶是動物。

示例一: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
// C++ program to demonstrate inheritance

#include <iostream>
using namespace std;

// base class
class Animal {

public:
void eat() {
cout << "I can eat!" << endl;
}
void sleep() {
cout << "I can sleep!" << endl;
}
};

// derived class
class Dog : public Animal {

public:
void bark() {
cout << "I can bark! Woof woof!!" << endl;
}
};

int main() {
// Create object of the Dog class
Dog dog1;

// Calling members of the base class
dog1.eat();
dog1.sleep();

// Calling member of the derived class
dog1.bark();

return 0;
}

/* OUTPUT
I can eat!
I can sleep!
I can bark! Woof woof!!
*/

dog1可以訪問基類Animal的所有成員,因為DogAnimal的派生。

1
2
3
// Calling members of the Animal class
dog1.eat();
dog1.sleep();

訪問protected保護的成員在C++繼承時尤其重要。

private成員一樣,protected在類之外無法訪問,但是可以通過派生的類和友類/函數來訪問。

protected如果我們想隱藏一個類的數據,但仍希望數據被派生類繼承,則需要成員。

示例二:C++ protected Members
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// C++ program to demonstrate protected members

#include <iostream>
#include <string>
using namespace std;

// base class
class Animal {

private:
string color;

protected:
string: type;

public:
void eat() {
cout << "I can eat!" << endl;
}

void sleep() {
cout << "I can sleep!" << endl;
}

void setColor(string clr) {
color = clr;
}

string getColor() {
return color;
}
};

// derived class
class Dog : public Animal {

public:
void setType(string yp) {
type = tp;
}

void displayInfo(string c) {
cout << "I am a " << type << endl;
cout << "My color is " << c << endl;
}

void bark() {
cout << "I can bark! Woof woof!!" << endl;
}
};

int main() {
// Create object of the Dog class
Dog dog1

// Calling members of the base class
dog1.eat();
dog1.sleep();
dog1.setColor("black");

// Calling member of the derived class
dog1.bark();
dog1.setType("mammal");

// Using getColor() of dog1 as argument
// getColor() returns string data
dog1.displayInfo(dog1.getColor());

return 0;
}

/* OUTPUT
I can eat!
I can sleep!
I can bark! Woof woof!!
I am a mammal
My color is black
*/

變量typeprotected,可以從派生類Dog訪問。我們可以看到這個在Dog中被我們使用函數setType()初始化。

另一方面,privated變量color不能在Dog中初始化。

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

public:
void setColor(string clr) {
// Error : member "Animal::color" is inaccessible
color = clr;
}
};

關鍵字protected隱藏數據,我們不能直接從對象Dog或類Animal訪問。

1
2
// Error: member "Animal::type" is inaccessable
dog1.type = "mammal";
C++繼承中的訪問模式

我們可以通過public來訪問類,也可以通過關鍵字privateprotected繼承類,例如:

1
2
3
4
5
6
7
8
9
10
class Animal {
// code
};

class Dog : private Animal {
// code
};
class Cat : protected Animal {
// code
};

我們把這種設定派生類的方法稱為**訪問模式(Access Modes)**。

  1. public:如果在public模式吸納聲明了派生類,則派生類將繼承基類的成員。
  2. private:基類的所有成員都會在派生類中變成private
  3. protected:基類中的成員都會在派生類中變成protected
繼承中的成員函數重寫

假設基類和派生類的成員函數具有相同的名稱和參數。

如果我們創建派生類的對象並嘗試訪問該成員函數,則將調用派生類中的成員函數,而不是基類中的成員函數,派生類中的成員函數將覆蓋基類的成員函數。


二十五:C++繼承訪問控制

在C++繼承中,我們可以在不同的訪問模式下從基類派生一個子類,例如:

1
2
3
4
5
6
7
class Base {
... .. ...
};

class Derived : public Base {
... .. ...
};

public是代碼中的關鍵字:

1
class Derived : public Base

這意味著我們從公共模式下,從基類創建了派生類。另外,我們也可從protected和private模式派生類。

這三個關鍵字public, protectedprivate在C++中被稱為**訪問說明符(access specifiers)**。

C++中的public, protected&private繼承

三種繼承具有以下的特點:

NOTE

派生類無法訪問基類的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
calss Base {
public:
int x;
protected:
int y;
private:
int z;
};

class PublicDerived: public Base {
// x is public
// y is protected
// z is not accessible from PublicDerived
};

class ProtectedDerived: protected Base {
// x is protected
// y is protected
// z is not accessible from ProtectedDerived
};

class PrivateDerived: private Base {
// x is private
// y is private
// z is not accessible from PrivateDerived
}
示例一:C++ public Inheritance
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
// C++ program to demonstrate the working of public inheritance

#include <iostream>
using namespace std;

class Base {
private:
int pvt = 1;

protected:
int prot = 2;

public:
int pub = 3;

// function to access private member
int getPVT() {
return pvt;
}
};

class PublicDerived : public Base {
public:
// function to access protected member from Base
int getProt() {
return prot;
}
};

int main() {
PublicDerived object1;
cout << "Private = " << object1.getPVT() << endl;
cout << "Protected = " << object1.getPVT() << endl;
cout << "Public = " << object1.pub << end;
return 0;
}

/* OUTPUT
Private = 1
Protected = 2
Public = 3
*/

在這裡,我們得到的PublicDerived來自於Base的公共模式。

PublicDerived 中:

1.prot被作為protected模式繼承。

2.pubgetPVT作為public模式繼承。

3.pvt不能被訪問,因為是Base裡面的私有成員。

雖然private和protected成員不能被訪問,但是我們可以創建public函數getPVT()getProt()來訪問他們:

1
2
3
4
5
// Error: member "Base::pvt" is inaccessible
cout << "Private = " << object1.pvt;

// Error: member "Base::prot" is inaccessible
cout << "Protected = " << object1.prot;
示例二:C++ protected Inheritance
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
// C++ program to demonstrate the working of protected inheritance

#include <iostream>
using namespace std;

class Base {
private:
int pvt = 1;

protected:
int prot = 2;

public:
int pub = 3;

// function to access private member
int getPVT() {
return pvt;
}
};

class ProtectedDerived : protected Base {
public:
// function to access protected member from Base
int getProt() {
return prot;
}

// function to access public member from Base
int getPub() {
return pub;
}
};

int main() {
ProtectedDerived object1;
cout << "Private cannot be accessed." << endl;
cout << "Protected = " << object1.getProt() << endl;
cout << "Public = " << object1.getPub() << endl;

return 0;
}

/* OUTPUT
Private cannot be accessed.
Protected = 2
Public = 3
*/

ProtectedDerived中:

眾所周知,protected成員不能被直接訪問。

我們不能從ProtectedDerived中使用getPVT()。這也是為什麼我們需要創建getPub()函數來訪問ProtectedDerived中的pub變量。

1
2
3
4
5
// Error: member "Base::getPVT()" is inaccessible
cout << "Private = " << object1.getPVT();

// Error: member "Base::pub" is inaccessible
cout << "Public = " << object1.pub;
C++ private Inheritance
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
// C++ program to demonstrate the working of private inheritance

#include <iostream>
using namespace std;

class Base {
private:
int pvt = 1;

protected:
int prot = 2;

public:
int pub = 3;

// function to access private member
int getPVT() {
return pvt;
}
};

class PrivateDerived : private Base {
public:
// function to access protected member from Base
int getProt() {
return prot;
}

// function to access private member
int getPub() {
return pub;
}
};

int main() {
PrivateDerived object1;
cout << "Private cannot be accessed." << endl;
cout << "Protected = " << object1. getProt() << endl;
cout << "Public = " << object1.getPub() << endl;

return 0;
}

/* OUTPUT
Private cannot be accessed.
Protected = 2
Public = 3
*/

這裡,我們通過private模式從Base派生了PrivateDerived

PrivateDerived 中:

所以我們不能在PrivateDerived中使用getPVT(),這也是為什麼我們需要在PrivateDerived創建getPub()函數來獲取pub變量。

1
2
3
4
5
// Error: member "Base::getPVT()" is inaccessible
cout << "Private = " << object1.getPVT();

// Error: member "Base::pub" is inaccessible
cout << "Public = " << object1.pub;

二十六:C++函數覆蓋

眾所周知,繼承是OOP的一項功能,它讓我們可以從基類創建派生類,派生類繼承基類的功能。

假設在派生類和基類中都定義了相同的函數。現在,如果我們使用派生類的對象調用此函數,則執行派生類的函數。

這在C++中稱為函數覆蓋(function overriding),派生類中的函數將覆蓋基類中的函數。

示例一:C++ Function Overriding
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
// C++ progam to demonstrate function overriding

#include <iostream>
using namespace std;

class Base {
public:
void print() {
cout << "Base Function" << endl;
}
};

class Derived : public Base {
public:
void print() {
cout << "Derived Function" << endl;
}
};

int main() {
Derived derived1;
derived1.print();

return 0;
}

/* OUTPUT
Derived Function
*/

在這裡print()BaseDerived中都有被定義。當我們喚起print()函數時,會因為Derived中覆蓋了Base的函數,而執行Derived的函數。

訪問C++中的覆蓋函數,訪問基類中的被覆蓋函數,我們會使用範圍解析運算符::

我們也可以訪通過基類的指針指向派生類的對象,然後從指針調用函數來訪問,覆蓋的函數。

示例二:C++ Function Overriding
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
// C++ program to access overridden function
// in main() using the scope resolution operator ::

#include <iostream>
using namespace std;

class Base {
public:
void print() {
cout << "Base Function" << endl;
}
};

class Derived : public Base {
public:
void print() {
cout << "Derived Function" << endl;
}
};

int main() {
Derived derived1, derived2;
derived1.print();

// access print() function of the Base class
derived2.Base::print();

return 0;
}

/* OUTPUT
Deirived Function
Base Function
*/

我們通過設置作用域來訪問基類函數:

1
derived2.Base::print();
示例三: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
// C++ program to call teh overridden function
// from a member function of the derived class

#include <iostream>
using namespace std;

class Base {
public:
void print() {
cout << "Base Function" << endl;
}
};

class Derived : public Base {
public:
void print() {
cout << "Derived Function" << endl;

// call overridden function
Base::print();
}
};

int main() {
Derived derived1;
derived1.print();

return 0;
}

/* OUTPUT
Derived Function
Base Function
*/

在這個程序中,我們調用了被覆蓋的函數在Derived類自身完成。

1
2
3
4
5
6
7
class Derived : public Base {
public:
void print() {
cout << "Derived Function" << endl;
Base::print();
}
};

Base::print()Derived類中調用了覆蓋函數。

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 access overridden function using pointer
// of Base type that points to an object of Derived class

#inlcude <iostream>
using namespace std;

class Base {
public:
void print() {
cout << "Base Function" << endl;
}
};

class Derived : public Base {
public:
void print() {
cout << "Derived Function" << endl;
}
};

int main() {
Derived derived1;

// pointer of Base type taht points to derived1
Base* ptr = &derived1;

// call function of Base class using ptr
ptr->print();

return 0;
}

/* OUTPUT
Base Function
*/

在這個程序中,我們創建了Base的指針ptr,這個指針指向Derived對象的derived1

1
2
// pointer of Base type that points to derived1
Base* ptr = &derived1;

當我們使用指針調用print()函數,它會調用Base被覆蓋的函數。

1
2
// call function of Base class using ptr
ptr->print();

這是因為ptr雖然指向Derived對象,但是實際上是Base的類型,所以調用的成員函數是Base

為了覆蓋Base函數而不是訪問它,我們需要使用Base中的虛函數。


二十七:C++繼承類型

繼承是面向對象編程語言的核心功能之一。它允許軟件開發人員從現有的類派生處一個新的類。派生類繼承基類的功能。

C++編程中有多種繼承模型。

C++多層繼承 Multilevel Inheritance

在C++程序中,你不僅可以從一個基類派生出一個類,你也可以從一個派生類中派生類,這種繼承形式被稱為多層繼承(multilevel inheritance)

1
2
3
4
5
6
7
8
9
10
11
12
class A
{
... .. ...
};
class B: public A
{
... .. ...
};
class C: public B
{
... .. ...
};

這裡,B是從基類A中派生的,C是從B中派生的。

示例一: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
#include <iostream>
using namespace std;

class A
{
public:
void display()
{
cout << "Base class content.";
}
};

class B : public A
{

};

class C : public B
{

};

int main()
{
C obj;
obj.display();
return 0;
}

/* OUTPUT
Base class content.
*/

在項目中,類CB的派生,BA的派生。

Cobj對象是被定義在main()的函數。當display()函數被調用,display()在類A中存在,所以會執行A中的函數,而如果C中有displa()函數,則會執行C中的函數,這個過程是函數覆蓋。

C++多重繼承

在C++程序中,一個類可以被派生通過超過一個的父級類。例如一個類Bat可以被從基類MammalWingedAnimal派生。因為蝙蝠是mammal也是winged animal。

C++多重繼承 Multiple Inheritance
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
#include <iostream>
using namespace std;

class Mammal {
public:
Mammal()
{
cout << "Mammals can give direct birth." << endl;
}
};

class WingedAnimal {
public:
WingedAnimal()
{
cout << "Winged animal can flap." << endl;
}
};

class Bat: public Mammal, public WingedAnimal {

};

int main()
{
Bat b1;
return 0;
}

/* OUTPUT
Mammals can give direct birth.
Winged animal can flap.
*/
多重繼承中的歧義

多重繼承最明顯的問題發生在函數覆蓋期間。

假設兩個基類具有相同的函數,但在派生類中未重寫該函數。

如果嘗試使用派生配的對象調用該函數,則編譯器會顯示錯誤。這是因為編譯器不知道該調用哪個函數。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class base1
{
public:
void someFunction()
{... .. ...}
};
class base2
{
void someFunction()
{... .. ...}
};
class derived : public base1, public base2
{

};

int main()
{
derived obj;

obj.someFunction() // Error!
}

這個問題可以通過使用範圍解析函數來處理,選擇類base1或者類base2的函數。

1
2
3
4
5
int main()
{
obj.base1::someFunction(); // Function of base1 class is called
obj.base2::someFunction(); // Function of base2 class is called
}
C++層次繼承 Hierarchical Inheritance

如果從基類繼承多個類,則稱為層次繼承。在分層繼承中,子類中共有的所有函數都包含在基類中。

例如:物理,化學,生物,都來自科學學科。

層次繼承的語法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class base_class {
... .. ...
}

class first_derived_class: public base_class {
... .. ...
}

class second_derived_class: public base_class {
... .. ...
}

class third_derived_class: public base_class {
... .. ...
}

二十八:C++友函數與友類

數據隱藏是面向對象編程的基本概念。它限制了類外部對private成員的訪問。

同樣,protected成員只能由派生類訪問,並且不能從外部訪問。例如:

1
2
3
4
5
6
7
8
9
10
11
class MyClass {
private:
int member1;
}

int main() {
MyClass obj;

// Error! Cannot access private members from here.
obj.member1 = 5;
}

但是C++中有一個稱為友函數的函數,可以打破規則,允許我們從外部訪問類的成員函數。同樣還有一個友類,我們在後半部分學習。

C++友函數 friend Function

一個友函數可以訪問類的private和protected數據。我們friend在類的主體中使用關鍵字聲明這是一個友函數。

1
2
3
4
5
class className {
... .. ...
friend returnType functionName(arguments);
... .. ...
}
示例一:Woring of friend Function
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;

class Distance {
private:
int meter;

// friend function
friend int addFive(Distance);

public:
Distance() : meter(0) {}
};

// friend function definition
int addFive(Distance d) {

// accessing private members from the friend function
d.meter += 5;
return d.meter;
}

int main() {
Distance D;
cout << "Distance: " << addFive(D);

return 0;
}

/* OUTPUT
Distance: 5
*/

這裡addFive()是一個友函數,可以訪問privatepublic的數據成員。

友函數更有意義的用途是對兩個不同類的對象進行操作。友函數會非常有幫助。

示例二:添加兩個不同類的成員
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
// Add members of two different classes using friend functions

#include <iostream>
using namespace std;

// forward declaration
class ClassB;

class ClassA {

public:
// constructor to initialize numA to 12
ClassA() : numA(12) {}

private:
int numA;

// friend function declaration
friend int add(ClassA, ClassB);
};

class ClassB {

public:
// constructor to initialize numB to 1
ClassB() : numB(1) {}

private:
int numB;

// friend function declaration
friend int add(ClassA, ClassB);
};

// access members of both classes
int add(ClassA objectA, ClassB objectB) {
return (objectA.numA + objectB.numB);
}

int main() {
ClassA objectA;
ClassB objectB;
cout << "Sum: " << add(objectA, objectB);
return 0;
}

/* OUTPUT
Sum: 13
*/

在此程序中,ClassAClassB都聲明了友函數add()。因此,該函數可以訪問兩個類的private函數。

這裡要注意的是友函數ClassA使用了ClassB。但是我們沒有定義ClassB,所以我們需要將ClassB在程序中向前聲明。

1
2
// forward declaration
class ClassB;
C++友類

我們還可以使用friend關鍵字在C++使用友類,例如:

1
2
3
4
5
6
7
8
9
10
class ClassB;
class ClassA {
// ClassB is a friend class of ClassA
friend class ClassB;
... .. ...
}

class ClassB {
... .. ...
}

將某個類聲明為友類,友類的所有成員函數都會變成友函數,由於ClassB是友類,我們可以從ClassB中訪問所有的ClassA成員,但是我們不能從ClassA訪問ClassB,因為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
// C++ program to demonstrate the working of friend class

#include <iostream>
using namespace std;

// forward declaration
class ClassB;

class ClassA {
private:
int numA;

// friend class declaration
friend class ClassB;

public:
// constructor to initialize numA to 12
ClassA() : numA(12) {}
};

class ClassB {
private:
int numB;

public:
// constructor to initialize numB to 1
ClassB() : numB(1) {}

// member function to add numA
// from ClassA and numB from ClassB
int add() {
ClassA objectA;
return objectA.numA + numB;
}
};

int main() {
ClassB objectB;
cout << "Sum: " << objectB.add();
return 0;
}

/* OUTPUT
Sum: 13
*/

ClassBClassA的友類,因此,ClassB可以訪問ClassA的成員,在ClassB中我們創建了函數add()返回numAnumB的和。

因為ClassB是一個友類,我們可以在ClassB中創建ClassA的對象。


二十九:C++虛函數

虛函數是基類中的成員函數,我們希望在派生類中重新定義它。

在基類中使用虛函數,確保函數被覆蓋,這適用於基類的指針指向派生類對象的情況。

例如,參考以下代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Base {
public:
void print() {
// code
}
};

class Derived : public Base {
public:
void print() {
// code
}
};

如果我們創建類Base的指針,指向類Derived的對象並調用該函數print(),那麼它將調用類Baseprint()

換句話說,函數Base的成員沒有被重寫。

1
2
3
4
5
6
7
int main() {
Derived derived1;
Base* base1 = &derived1;

// calls function of Base class
base->print();
}

為了避免這種情況,我們定義類Baseprint()函數為虛函數,通過使用虛擬關鍵字。

1
2
3
4
5
6
class Base {
public:
virtual void print() {
// code
}
};

Virtual functions are an integral part of polymorphism in C++. To learn more, check our tutorial on C++ Polymorphism.

示例一: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
#include <iostream>
using namespace std;

class Base {
public:
virtual void print() {
cout << "Base Function" << endl;
}
};

class Derived : public Base {
public:
void print() {
cout << "Derived Function" << endl
}
};

int main() {
Derived derived1;

// pointer of Base type that points to derived1
Base* base1 = &derived1;

// calls member function of Derived class
base1->print();

return 0;
}

/* OUTPUT
Derived Function
*/

這裡,我們已經聲明了Baseprint()函數作為虛函數。所以函數被覆蓋,即使我們使用了Base的指針指向Derived的對象derived1

c++覆蓋標識符

C++11為我們提供了一個新的標識符override,該標識符對於避免使用虛函數時的錯誤非常有用。

該標識符指定派生類的成員函數,這些成員函數將覆蓋基類的成員函數。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Base {
public:
virtual void print() {
// code
}
};

class Derived : public Base {
public:
void print() override {
// code
}
};

如果我們在類Derived中使用函數原型並在類之外定義該函數,那麼我們將使用以下代碼:

1
2
3
4
5
6
7
8
9
10
class Derived : public Base {
public:
// function prototype
void print() override;
};

// function definition
void Derived::print() {
// code
}
使用C++覆蓋

使用虛函數時,在聲明派生類的成員函數時可能會出錯。

使用override標識符會提示編譯器在出現錯誤時顯示錯誤信息,不然程序會執行變異,虛擬函數不會被覆蓋。

其中可能的一些錯誤是:

C++虛函數的使用

假設我們有一個基類Animal和派生類DogCat

假設每個類都有一個名為type的數據成員,假設止血變量是通過他們各自的構造函數初始化的。

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
class Animal {
private:
string type:
... .. ...
public:
Anima(): type("Animal") {}
... .. ...
};

class Dog : public Animal {
private:
string type;
... .. ...
public:
Animal(): type("Dog") {}
... .. ...
};

class Cat : public Animal {
private:
string type;
... .. ...
public:
Animal(): type("Cat") {}
... .. ...
};

現在,讓我們假設我們的程序要求我們的public為每個類創建兩個函數:

1.getType()返回type

2.print()打印type

我們可以在每個類中分別創建兩個函數並覆蓋他們,但是這冗長又乏味。

或者我們在類中將getType()在類Animal中虛化,然後創建單獨的print()函數,函數接受Animal的指針作為參數,然後我們使用單個函數來覆蓋虛函數。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Animal {
... .. ...
public:
... .. ...
virtual string getType {...}
};

... .. ...
... .. ...

void print(Animal* ani) {
cout << "Animal: " << ani->getType() << endl;
}

這會使代碼更短,更簡潔,重複性更低。

示例二: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
62
63
64
65
66
67
// C++ program to demonstrate the use of virtual function

#include <iostream>
#include <string>
using namespace std;

class Animal {
private:
string type;

public:
// constructor to initialize type
Animal() : type("Animal") {}

// declare virtual function
virtual string getType() {
return type;
}
};

class Dog : public Animal {
private:
string type;

public:
// constructor to initialize type
Dog() : type("Dog") {}

string getType() override {
return type;
}
};

class Cat : public Animal {
private:
string type;

public:
// constructor to initialize type
Cat() : type("Cat") {}

string getType() override {
return type;
}
};

void print(Animal* ani) {
cout << "Animal: "<< ani->getType() << endl;
}

int main() {
Animal* animal1 = new Animal();
Animal* dog1 = new Dog();
Animal* cat1 = new Cat();

print(animal1);
print(dog1);
print(cat1);

return 0;
}

/* OUTPUT
Animal: Animal
Animal: Dog
Animal: Cat
*/

這裡,我們使用了虛函數getType()和一個Animal的指針ani避免在每個類中都重複print()函數。

1
2
3
void print(Animal* ani) {
cout << "Animal: " << ani->getType() << endl;
}

main(),我們創建了三個Animal指針,動態創建AnimalDogCat的對象。

1
2
3
4
// dynamically create objects using Animal pointers
Animal* animal1 = new Animal();
Animal* dog1 = new Dog();
Animal* cat1 = new Cat();

當然後我們使用指針調用print()函數:

1.當print(animal1)被調用,指針指向Animal對象。然後虛函數類Animal中執行print()

2.當print(dog1)被調用,指針指向Dog對象。虛函數被覆蓋,函數Dog內執行print()

3.當print(cat1)被調用,指針指向Cat對象。虛函數被覆蓋,函數Cat內執行print()


三十:C++模板

模板是C++的強大功能,可以讓你編寫通用程序。簡而言之,你可以使用模版創建一個函數或一個類來處理不同的數據類型。

模板通常在較大的代碼庫中使用,目的是實現代碼的可重用性和靈活性。

模板的概念可以有兩種不同的方式使用:

函數模板

函數模板的工作方式與普通函數相似,只有一個不同之處。

單個函數模板可以一次處理不同的數據類型,但是單個普通函數只能處理一組數據類型。

通常,如果需要對兩種或多種類型的數據執行相同的操作,則可以使用函數重載來創建具有所需函數聲明的兩個函數。

但是,更好的方法是使用函數模板,因為您可以執行較少的代碼並維護代碼來執行相同的任務。

如何聲明函數模板

通過關鍵字template並在模板參數/s 接入<>跟隨在函數聲明之後。

1
2
3
4
5
template <class T>
T someFunction(T arg)
{
... .. ...
}

T是一個接受不同類型數據的模板參數,class是一個關鍵字。

你可以使用關鍵字typename取代class的例子。

當數據類型的參數被傳遞到someFunction(),編譯器會給someFunction()數據類型生成新的版本。

示例一:函數模板-找到最大數
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
// If two characters are passed to function template, character with larger ASCII value is displayed.

#include <iostream>
using namespace std;

// template function
template <class T>
T Large(T n1, T n2)
{
return (n1 > n2) ? n1 : n2;
}

int main()
{
int i1, i2;
float f1, f2;
char c1, c2;

cout << "Enter two integers: \n";
cin >> i1 >> i2;
cout << Large(i1, i2) << " is larger." << endl;

cout << "\n Enter two floating-point numbers: \n";
cin >> f1 >> f2;
cout << Large(f1, f2) << " is larger." << endl;

cout << "\nEnter two characters:\n";
cin >> c1 >> c2;
cout << Large(c1, c2) << " has larger ASCII value";

return 0;
}

/* OUTPUT
Enter two integers:
5
10
10 is larger.

Enter two floating-point numbers:
12.4
10.2
12.4 is larger.

Enter two characters:
z
Z
z has larger ASCII value.
*/

在上面的程序中,我們定義了一個可以接受兩個參數n1n2的函數模板Large()。T表示參數可以是任何數據類型。

Large()函數使用簡單的條件曹族喔返回兩個參數裡面最大的一個。

main()函數,有聲明三種不同數據類型的變量:intfloatchar。然後將變量Large()作為普通函數傳遞到函數模板。

在運行時,將整數傳遞給模板函數時,編譯器知道它必須生成一個Large()函數來接受int參數。

同樣,當傳遞floatchar時,它知道自變量數據類型並相應地生成Large()函數。

示例二:使用函數模板交換數據
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
#include <iostream>
using namespace std;

template <typename T>
void Swap(T &n1, T &n2)
{
T temp;
temp = n1;
n1 = n2;
n2 = temp;
}

int main()
{
int i1 = 1, i2 = 2;
float f1 = 1.1, f2 = 2.2;
char c1 = 'a', c2 = 'b';

cout << "Before passing data to function template.\n";
cout << "i1 = " << i1 << "\ni2 = " << i2;
cout << "\nf2 = " << i2 << "\nf2 = " << f2;
cout << "\nc1 = " << c1 << "\nc2 = " << c2;

Swap(i1, i2);
Swap(f1, f2);
Swap(c1, c2);

cout << "\n\nAfter passing data to function template. \n";
cout << "i1 = " << i1 << "\ni2 = " << i2;
cout << "\nf1 = " << f1 << "\nf2 = " << f2;
cout << "\nc1 = " << c1 << "\nc2 = " << c2;

return 0;
}

/* OUTPUT
Before passing data to function template.
i1 = 1
i2 = 2
f1 = 1.1
f2 = 2.2
c1 = a
c2 = b

After passing data to function template.
i1 = 2
i2 = 1
f1 = 2.2
f2 = 1.1
c1 = b
c2 = a
*/

在此程序中,不是通過傳遞值來調用函數,而是通過引用來進行調用。

Swap()函數模板應用需要兩個參數來交換它們。

Class模板

與函數模板,你也可以通過類來創建類模板。

你需要一個適用所有類的類實現,只是所使用的數據類型不同。

通常,你需要為每種數據類型創建一個不同的類,或者在一個類中創建不同的成員變量和函數。

這將不必要的擴大你的代碼庫,並難以維護,因為更改時應對所有類/所有類作用的函數/函數。類模板對所有數據類型復用代碼變得容易。

如何聲明一個類模板?

1
2
3
4
5
6
7
8
9
template <class T>
class className
{
... .. ...
public:
T var;
T someOperation (T arg);
... .. ...
};

在上面的聲明中,T是template參數,它是所使用數據類型的佔位符。

在class中,一個成員變量var和成員函數someOperation()都是typeT

如何創建類模板對象?

要創建類模板對象,你需要在<>內定義數據類型。

1
className<dataType> classObject;

舉例:

1
2
3
className<int> classObject;
className<float> classObject;
className<string> classObject;
示例三:使用類模板的簡單計算器

程序使用類模板對兩個數字進行加,減,乘除運算。

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
#include <iostream>
using namespace std;

template <clas T>
class Calculator
{
private:
T num1, num2;

public:
Calculator(T n1, T n2)
{
num1 = n1;
num2 = n2;
}

void displayResult()
{
cout << "Numbers are: " << num1 << " and " << num2 << "." << endl;
cout << "Addition is: " << add() << endl;
cout << "Subtraction is: " << subtract() << endl;
cout << "Product is: " << multiply() << endl;
cout << "Division is: " << divide() << endl;
}

T add() { return num1 + num2; }
T subtract() { return num1 - num2; }
T multiply() { return num1 * num2; }
T divide() { return num1 / num2; }
};

int main()
{
Calculator<int> intCalc(2, 1);
Calculator<float> floatCalc(2.4, 1.2);

cout << "Int results: " << endl;
intCalc.displayResult();

cout << endl << "Float results: " << endl;
floatCalc.displayResult();

return 0;
}

/* OUTPUT
Int results:
Numbers are: 2 and 1.
Addition is: 3
Subtraction is: 1
Product is: 2
Division is: 2

Float results:
Numbers are: 2.4 and 1.2.
Addition is: 3.6
Subtraction is: 1.2
Product is: 2.88
Division is: 2
*/

在上面的程序中,Calculator聲明了一個類模板。

該類包含兩個類型為的私有成員Tnum1num2。以及初始化成員的構造函數。

它還包含公共成員函數,用戶計算數字的加減乘除,這些數返回用戶定義的數據類型的值。displayResult()將最終輸出到屏幕的函數。

在該main()函數,分別為數據類型創建兩個Calculator對象:和。

使用構造函數初始化值:intCalc, floatCalc, int, float

我們在創建對象時使用intfloat。這些告訴編譯器用於類創建的數據類型。

這將為int創建每個類的定義float,然後相應地使用它們。

然後,displayResult()兩個對象都被調用,這將執行計算操作並顯示。

About this Post

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