C++程序設(shè)計(jì)入門(上) 崔毅東

Introduction to C++ (Season 1)

Unit 1: Overview of C++

第1單元: 不識(shí)廬山真面目 – C++概覽

Section 1 : About This Course

第1節(jié):關(guān)于C++課程

"C++" and its father

  • C++ == C Plus Plus == CPP
  • Father of C++: Bjarne Stroustrup
Year C++ Standard Informal name
2014 ISO/IEC 14882:2014 C++14
2011 ISO/IEC 14882:2011 C++11
2007 ISO/IEC TR 19768:2007 C++TR1
2003 ISO/IEC 14882:2003 C++03
1998 ISO/IEC 14882:1998 C++98

Section 2 : Prelude : Aloha World!

第2節(jié):你好,世界!

Program Files (代碼文件/程序文件)

  • Header file
  • 頭文件
  • Source file
  • 源文件
Coding Conventions (編碼規(guī)范)

Why Coding Conventions?

  • 讓程序具有好的可讀性
  • “避免日后有人(或者自己)指著你的代碼罵娘:這特么誰(shuí)寫的破爛玩意”(來(lái)自:知乎-Gui Wulei。或在知乎搜索:編碼規(guī)范)

Google開源項(xiàng)目風(fēng)格指南(中文版)

geosoft.no的編碼風(fēng)格指南(英文版)

Section 1 : Primitive Data Types & Operations

第1節(jié):基本數(shù)據(jù)類型與運(yùn)算

Unit 3: More than C

第3單元:更上一層樓 – 超越C的語(yǔ)法

Review: typedef and #define
In C99
//C99: no "bool"
typedef int BOOL; //分號(hào)結(jié)尾
#define TRUE 1 //無(wú)分號(hào)
#define FALSE 0
typedef Blah Blah Blah NewTypeName
#define MACRONAME Blah-Blah-Blah

typedef unsigned int UInt;
typedef unsigned int* PInt;
3. Names representing types must be in mixed case starting with upper case.
3. 代表類型的名字必須首字母大寫并且其它字母大小寫混合
例如:Line, SavingsAccount

#define A_NAME "alpha"
#define YOU 2
5. Named constants (including enumeration values) must be all uppercase
using underscore to separate words.
5. 命名常量(包括枚舉值)必須全部大寫并由下劃線分隔單詞
例如:MAX_ITERATIONS, COLOR_RED, PI

Data type : bool (布爾類型)

In C++: bool, true, false
bool isMyBook;
bool isRunning = false;
bool isBoy( );
bool hasLicense();
bool canWork();
bool shouldSort();

bool and int
 0 -> false
 true -> 1
 non-zero -> true
Example
 'a' -> ?
26. The prefix is should be used for boolean variables and methods.
26. 布爾變量/函數(shù)的命名應(yīng)使用前綴“is”
例如:isSet, isVisible, isFinished, isFound, isOpen

Example of bool (bool示例)

#include <iostream>
int main() {
  bool isAlpha;
  isAlpha = false;
  if (!isAlpha) {
    std::cout << "isAlpha=" << isAlpha << std::endl;
    std::cout << std::boolalpha <<
                 "isAlpha=" << isAlpha << std::endl;
  }
  return 0;
}
/*
39. The incompleteness of split lines must be made obvious.
39. 斷行必須很明顯。
在逗號(hào)或運(yùn)算符后換行,新行要對(duì)齊
The output
isAlpha=0
isAlpha=false
*/

Type conversion (類型轉(zhuǎn)換)

C++ Style: static_cast<type> value
cout << static_cast<double>(1) / 2;
cout << 1 / 2;
//45. Type conversions must always be done explicitly. Never rely on implicit type conversion.
//45. 類型轉(zhuǎn)換必須顯式聲明。永遠(yuǎn)不要依賴隱式類型轉(zhuǎn)換
//例如:floatValue = static_cast<float>(intValue); // NOT: floatValue = intValue;

Declaring and Initializing Variables (變量初始化)

int x = 1; //C & C++
int x(1); //C++, OO style
int x; x(1); //Error!

Section 2 : Function
第2節(jié):函數(shù)

Scope of Variable

變量作用域

Scope of Local Variables 1 (局部變量的作用域)

Variables Position (位置) Scope (作用域)
in C89 must be defined in the front of function body(必須在函數(shù)體前面定義) starts from it's definition to the end of the function(從定義位置到函數(shù)尾)
in C++ can be defined anywhere inside the functionbody (可在函數(shù)體內(nèi)任意位置定義) starts from it's definition to the end of the block (e.g.function body/for body/…) (從定義位置到塊尾)

Unary Scope Resolution (一元作用域解析運(yùn)算符)

If a local variable name is the same as a global variable name, you can accessthe global variable using ::globalVariable. (局部變量名與全局變量名相同時(shí),可使用 :: 訪問全局變量)
The :: operator is known as the unary scope resolution.

#include <iostream>
using namespace std;
int v1 = 10;
int main() {
  int v1 = 5;
  cout << "local variable v1 is " << v1 << endl;
  cout << "global variable v1 is " << ::v1 << endl;
  return 0;
}

Overloading Functions

重載函數(shù)

max() : works only with the int datatype (只用于int)

int max(int num1, int num2)
{
  if (num1 > num2)
    return num1;
  else
    return num2;
}

But what about floating-point numbers? (如果遇到浮點(diǎn)數(shù)怎么辦)
The solution is to create another function with the same name but different parameters. (方法是生成一個(gè)同名不同參數(shù)的函數(shù))

編譯器如何匹配重載函數(shù)調(diào)用?
-> 看參數(shù):

  • 個(gè)數(shù)
  • 類型
  • 順序
Ambiguous Invocation (二義調(diào)用)
?Ambiguous Invocation: There may be two or more possible matches for an
invocation of a function, but the compiler cannot determine the most specific
match. (某函數(shù)調(diào)用有多個(gè)匹配項(xiàng),但編譯器無(wú)法確定正確的項(xiàng))
? Ambiguous invocation is a compilation error. (會(huì)導(dǎo)致編譯錯(cuò)誤)
#include <iostream>
using namespace std;
int maxNumber(int num1, double num2)
{
  if (num1 > num2)
    return num1;
  else
    return num2;
}
double maxNumber(double num1, int num2)
{
  if (num1 > num2)
    return num1;
  else
    return num2;
}
int main()
{
  cout << maxNumber(1, 2) << endl;
  return 0;
}

Default Argument

默認(rèn)參數(shù)值

C++ allows you to declare functions with default argument values.
(可以聲明帶默認(rèn)參數(shù)值的函數(shù))
The default values are passed to the parameters when a function is invoked without the arguments.
(無(wú)參調(diào)用函數(shù)時(shí),默認(rèn)值會(huì)被傳遞給形式參數(shù))

參數(shù)列表中默認(rèn)值參數(shù)應(yīng)后置
void t3 (int x, int y=0, int z=0);
void t4 (int x=0, int y=0, int z=0);
t3 (1); // y,z: default value
t4 (1, 2); // z: default value

(C++03/C++11) A default argument shall not be redefined by a later
declaration (not even to the same value).

void printArea(double radius = 1);
int main(){
  printArea();
  printArea(4);
  return 0;
}
void printArea(double radius) {
  // Do something
}

Inline Functions

內(nèi)聯(lián)函數(shù)

Using functions in a program:
Advantages(優(yōu)點(diǎn)): 易讀易維護(hù)
Drawbacks (缺點(diǎn)): 運(yùn)行時(shí)性能開銷
? 函數(shù)調(diào)用時(shí):參數(shù)及部分CPU寄存器的
寄存器內(nèi)容進(jìn)棧,控制流跳轉(zhuǎn)
? 函數(shù)返回時(shí):返回值及寄存器值出棧,
控制流跳轉(zhuǎn)

Inline functions
? 目的:減小性能開銷
? 方法:代碼插入到調(diào)用處
? 結(jié)果:導(dǎo)致程序變大

?How to declare an inline function
inline int max (int a, int b) {
  return (a > b ? a : b);
}
?But NOT:
int max (int a, int b);
// Call max()
inline int max (int a, int b) {
  return (a > b ? a : b);
}

Restrictions for inline function (內(nèi)聯(lián)函數(shù)的使用限制)
?Desire for short functions (適用于短函數(shù))
?NOT suitable for long functions thatare called in multiple places (不適于多處調(diào)用的長(zhǎng)函數(shù))
?內(nèi)聯(lián)函數(shù)只是一種編譯機(jī)制
?“inline”是對(duì)編譯器的請(qǐng)求,而不是命令。
?函數(shù)調(diào)用的開銷
? 對(duì)小的函數(shù)不可忽略
? 對(duì)重量級(jí)的函數(shù)是可以忽略的
?大多數(shù)編譯器并不把帶有循環(huán)、遞歸等或者代碼比較多的函數(shù)進(jìn)行內(nèi)聯(lián)編譯。

Section 3 : Reference & Dynamic Memory

第3節(jié):引用與動(dòng)態(tài)內(nèi)存管理

Reference

引用

Reference (引用)
?A reference is an alias for another variable. (引用就是另一個(gè)變量的別名)
?Any changes made through the reference variable are actually performed on the original variable(通過(guò)引用所做的讀寫操作實(shí)際上
是作用于原變量上). 
?To declare a reference variable:
int x;
int& rx = x;
?or
int x, &rx = x;
51. C++ pointers and references should have their
reference symbol next to the type rather than to the name.
51. C++指針與引用符號(hào)應(yīng)靠近其類型而非名字。
例如: float* x; // NOT: float *x;
int& y; // NOT: int &y;

Function Parameters: Pass By Reference (函數(shù)參數(shù):引用傳遞)
?You can use a reference variable as a parameter in a function and pass a
regular variable to invoke the function. (引用可做函數(shù)參數(shù),但調(diào)用時(shí)只需
傳普通變量即可)
?When you change the value through the reference variable, the original value
is actually changed. (在被調(diào)函數(shù)中改變引用變量的值,則改變的是實(shí)參的
值)

Comparision: 3 swap() functions

//pass by value
void swap(int x, int y){
int t;
t=x; x=y; y=t;
}
int main() {
int a(5), b(10);
cout << "Before: a=" << a <<
" b=" << b << endl;
swap( a, b );
cout << "After: a=" << a <<
"b=" << b << endl;
return 0;
}
Before: a=5 b=10
After: a=5 b=10

//pointer as formal params
void swap(int* x, int* y){
int t;
t=*x; *x=*y; *y=t;
}
int main() {
int a(5), b(10);
cout<< "Before: a=" << a <<
" b=" << b << endl;
swap( &a, &b );
cout<< "After: a=" << a <<
<<"b="<<b<<endl;
return 0;
}
Before: a=5 b=10
After: a=10 b=5

//reference as formal params
void swap(int& x, int& y){
int t;
t=x; x=y; y=t;
}
int main() {
int a(5), b(10);
cout<< "Before: a=" << a <<
" b=" << b << endl;
swap( a, b );
cout << "After: a=" << a <<
"b="<<b<<endl;
return 0;
}
Before: a=5 b=10
After: a=10 b=5

Dynamic Memory

動(dòng)態(tài)內(nèi)存管理

**Dynamic memory: Allocate/Release **

?C++中通過(guò)運(yùn)算符new申請(qǐng)動(dòng)態(tài)內(nèi)存
new <類型名> (初值) ; //申請(qǐng)一個(gè)變量的空間
new <類型名>[常量表達(dá)式] ; //申請(qǐng)數(shù)組
? 如果申請(qǐng)成功,返回指定類型內(nèi)存的地址;
? 如果申請(qǐng)失敗,返回空指針(整數(shù)0)。
?動(dòng)態(tài)內(nèi)存使用完畢后,要用delete運(yùn)算符來(lái)釋放。
delete <指針名>; //刪除一個(gè)變量/對(duì)象
delete []<指針名>; //刪除數(shù)組空間

70. "0" should be used instead of "NULL".
70. 用“0”代替“NULL” is part of the standard C library, but is made obsolete in C++.。
因?yàn)椤癗ULL”是C語(yǔ)言標(biāo)準(zhǔn)庫(kù)的內(nèi)容,但是在C++中已經(jīng)廢止了。

Dynamic memory: Examples

11 C C++
AllocateRelease malloc();free(); new delete
Example 1 char* s = (char*)malloc(1);free(s); char* s = new char(97);delete s;
Example 2 int* p = (int) malloc(410);free(p); int* p = new int[10];delete [] p;
Example 3 int** q = (int) malloc(4103);free(q); int** q = new int[10][3];int (*q)[3] = new int[10][3];(暫不做要求)delete [] p;
new
delete

char* s = new char(97);
delete s;
int* p = new int[10];
delete [] p;

int** q = new int[10][3];\\int** q = new int[10][3];error C2440: “初始化”: 無(wú)法從“int (*)[3]”轉(zhuǎn)換為“int **”、int (*q)[3] = new int[10][3];(暫不做要求)
delete [] p;

Section 4 : Simplified Memory Model for C/C++

第4節(jié):C/C++的簡(jiǎn)化內(nèi)存模型

Simplified Memory Model (C++的內(nèi)存模型)

  1. Stack (棧)
    ? 編譯器自動(dòng)分配釋放
  2. Heap (堆)
    ? 一般由程序員分配釋放,若程序員不釋放,程序結(jié)束時(shí)可能由OS回收
  3. Global/Static (全局區(qū)/靜態(tài)區(qū))
    ? 全局變量和靜態(tài)變量的存儲(chǔ)是放在一塊的。
    ? 可以簡(jiǎn)單認(rèn)為:
    ? 程序啟動(dòng)全局/靜態(tài)變量就在此處
    ? 程序結(jié)束釋放
  4. Constant (常量區(qū))
    ? 可以簡(jiǎn)單理解為所有常量都放在一起
    ? 該區(qū)域內(nèi)容不可修改

Example of memory allocation (C++程序的內(nèi)存示例)
?堆向高地址方向生長(zhǎng)
?棧向低地址方向生長(zhǎng)
常量區(qū) 全局/靜態(tài)區(qū) 堆 棧
0x1000-------------0xFFFF

Location of a variable (變量存放位置)

int arr[3];//全局/靜態(tài)區(qū)
int myFunc()
{
int a;//棧
char *p;//棧
char* str=“hello world”//str->棧,“hello world”->常量區(qū)
}

int myFunc1(int* pi)//棧
{
char *pc;//棧
pc= static_cast<char*> new char[8];//堆
}

普通變量?jī)?nèi)存模型
?普通變量
int a, b=0; a=b;
?a和b都是變量的名,對(duì)a和b的訪問實(shí)際上訪問的是a和b這兩個(gè)變量中存
儲(chǔ)的值
?a和b的地址分別是 &a 和 &b

數(shù)組內(nèi)存模型
?對(duì)于數(shù)組a[],a是數(shù)組a[]的首地址的別名
?要訪問每個(gè)數(shù)組元素的值,使用a[0], a[1],…
?要訪問一個(gè)地址所存的內(nèi)容,使用 “*”
? 訪問數(shù)組中第一個(gè)元素可以使用 *(a+0)
? 訪問數(shù)組中第二個(gè)元素 *(a+1)
a[]
a[0] a[1] a[2] a[3]

Section 5 : Const

第5節(jié):常量

?const datatype CONSTANTNAME = VALUE;
const double PI = 3.14159;
const int SIZE = 3;
int const X = 5;

?const in C vs in C++
? in C (C89), const means "ReadOnly Variable" (只讀變量)
? in C++, const means "Constant" (常量)

const int ARRAY_SIZE = 10;
int arr[ARRAY_SIZE]; //OK in C++, Error in C

5. Named constants (including enumeration values) must be all
uppercase using underscore to separate words.
5. 符號(hào)常量(包括枚舉值)必須全部大寫并用下劃線分隔單詞
例如:MAX_ITERATIONS, COLOR_RED, PI

const and pointers (常量與指針)
two features of a pointer(指針的兩個(gè)屬性):
? pointer variable (指針變量本身)
? data that the pointer points to (指針變量所指向的數(shù)據(jù))

const + pointer

指針 被指數(shù)據(jù)
variable variable
variable constant
constant variable
constant constant

A variable pointer to a constant value
?Shortly: Pointer to Constant (常量指針/常指針)
?特征:指針?biāo)赶虻膬?nèi)容不可以通過(guò)指針的間接引用(*p)來(lái)改變。

const int* p1;
const int x = 1;
p1 = &x; //指針 p1的類型是 (const int*)
*p1 = 10; // Error!

An invariable pointer to a variable value
Pointer Constant (指針常量)
? 指針本身的內(nèi)容是個(gè)常量,不可以改變。

int x = 1, y = 1;
int* const p2 = &x; //常量 p2的類型是 (int*)
*p2 = 10; // Okay! -> x=10
p2 = &y; // Error! p2 is a constant

數(shù)組名就是數(shù)組的首地址的別名?,F(xiàn)在可以說(shuō):數(shù)組名就是一個(gè)指針常
量。
Memory location of pointers (指針的內(nèi)存布局)

指針布局實(shí)例: (以下代碼在某函數(shù)內(nèi)部)
const int a = 5;
int b = 9;
const int* pa = &a; //pointer to constant
int* const pb = &b; //pointer constant

Summary (總結(jié))
?在前先讀,在前不變
? * (指針)和 const(常量) 誰(shuí)在前先讀誰(shuí) ;
? * 代表被指的數(shù)據(jù),名字代表指針地址
? const在誰(shuí)前面誰(shuí)就不允許改變。

關(guān)于指針和數(shù)組的關(guān)系,是C語(yǔ)言課程中非常重要的一個(gè)知識(shí)。
在這里僅給出一些結(jié)論性的內(nèi)容。如果你對(duì)該知識(shí)點(diǎn)還比較模糊,那么,思考清楚下面的結(jié)論,對(duì)你掌握指針與數(shù)組有很大幫助。
我們定義:
int iarray[5],*ip;
然后
ip=&iarray[0];
那么有如下結(jié)論:(<==>表示在一般情況下可以互換使用)
ip+k <==> &iarray[k] <==> iarray+k <==> value of ip + k*sizeof(int)
以及
*(ip+k) <==> iarray[k] <==> ip[k] <==> *(iarray+k)

Section 1 : Concepts of Class

第1節(jié):類的概念

Unit 4: Objects and Classes

第4單元: 物以類聚 –對(duì)象和類

Features of OO (面向?qū)ο蟮奶卣?
?Abstraction (抽象)
?Polymorphism (多態(tài))
?Inheritance (繼承)
?Encapsulation (封裝)

What does an object consist of? (對(duì)象由什么構(gòu)成)
An object has a unique identity, state, and behaviors.(對(duì)象具有唯一的標(biāo)識(shí)、狀態(tài)和行為)
? The state of an object consists of a set of data fields (also known as properties) with
their current values. (對(duì)象狀態(tài)由數(shù)據(jù)域(也稱為“屬性”)及其當(dāng)前值構(gòu)成)
? The behavior of an object is defined by a set of functions. (對(duì)象的行為由一組函數(shù)定義)

Classes
?A class uses variables(變量) to define data fields(定義數(shù)據(jù)域) and
functions(函數(shù)) to define behaviors(定義行為).
?Additionally, a class provides a special type of functions, known as
constructors, which are invoked to construct objects from the class. (類中有
一種特殊的“構(gòu)造函數(shù)”,在創(chuàng)建對(duì)象時(shí)被自動(dòng)調(diào)用)

C++ Data Types (C++數(shù)據(jù)類型分類)

C++ Data Types
structured
array struct union class
address
pointer reference
floating
float double long double
integral
char short int long bool

Section 2 : Create Objects and Access the members

第2節(jié):創(chuàng)建對(duì)象并訪問對(duì)象成員

Constructors:
? Initialize objects (構(gòu)造函數(shù):初始化對(duì)象)
? Has the same name as the defining class (與類同名)
? NO return value (including "void"); (無(wú)返回值)
? constructors can be overloaded (可重載)
? may be no arguments (可不帶參數(shù))

A class may be declared without constructors (類可不聲明構(gòu)造函數(shù))
1. A no-arg constructor with an empty body is implicitly declared in the class.
(編譯器會(huì)提供一個(gè)帶有空函數(shù)體的無(wú)參構(gòu)造函數(shù))
2. This constructor, called a default constructor is provided automatically only if no constructors are explicitly declared in the class.
(只有當(dāng)未明確聲明構(gòu)造函數(shù)時(shí),編譯器才會(huì)提供這個(gè)構(gòu)造函數(shù),并稱之為“默認(rèn)構(gòu)造函數(shù)”)
class Circle {
public:
  double radius;
  Circle() { }
};

Constructing Objects (創(chuàng)建對(duì)象)
? Without Arguments: (無(wú)參數(shù))
ClassName objectName;
? For example:
Circle circle1; // the no-arg constructor
// is invoked
? With Arguments: (帶參數(shù))
ClassName objectName(arguments);
? For Example:
Circle circle2(5.5);

class Circle {
public:
  double radius;
  Circle() {
  radius = 1;
  }
  Circle(double newRadius) {
  radius = newRadius;
  }
//……
};

**Object Member Access Operator(對(duì)象訪問運(yùn)算符) **
To access the data & functions of an object: (訪問對(duì)象中的數(shù)據(jù)和函數(shù))
? the dot operator (.), namely, the object member access operator.
objectName.dataField // 訪問對(duì)象的數(shù)據(jù)域
objectName.function(arguments) // 調(diào)用對(duì)象的一個(gè)函數(shù)

A Simple Circle Class

#include <iostream>
using namespace std;
class Circle {
public:
    // The radius of this circle
    double radius;
    // Construct a circle object
    Circle() {
    radius = 1;
    }
    // Construct a circle object
    Circle(double newRadius) {
    radius = newRadius;
    }
    // Return the area of this circle
    double getArea() {
    return radius * radius * 3.14159;
    }
};
int main() {
    Circle circle1;
    Circle circle2(5.0);
    cout << "The area of the circle of radius " <<
    circle1.radius << " is " << circle1.getArea() << endl;
    cout << "The area of the circle of radius " <<
    circle2.radius << " is " << circle2.getArea() << endl;
    // Modify circle radius
    circle2.radius = 100.0;
    cout << "The area of the circle of radius " <<
    circle2.radius << " is " << circle2.getArea() << endl;
return 0;
}

Section 3 : More on Creating Objects

第3節(jié):關(guān)于創(chuàng)建對(duì)象的更多細(xì)節(jié)

Naming Objects and Classes (為對(duì)象和類命名)
When you declare a custom class, capitalize the first letter of each word in aclass name; (聲明一個(gè)自定義的類時(shí),類名中的單詞要首字母大寫)
? for example, the class names Circle, Rectangle, and Desk.
The class names in the C++ library are named in lowercase. (C++標(biāo)準(zhǔn)庫(kù)中的類名是小寫的)
The objects are named like variables. (對(duì)象的命名方式與變量類似)

Class is a Type (類是一種數(shù)據(jù)類型)
?use primitive data types to define variables. (用基本數(shù)據(jù)類型定義變量)
?use class names to declare objects. In this sense, a class is also a data type. (用類名定義對(duì)象)

3. Names representing types must be in mixed case starting with upper case.
3. 代表類型的名字必須首字母大寫并且其它字母大小寫混合
例如:Line, SavingsAccount

Memberwise Copy (成員拷貝)
How to copy the contents from one object to the other?(如何將一個(gè)對(duì)象的內(nèi)容拷貝給另外一個(gè)對(duì)象)
? use the assignment operator(使用賦值運(yùn)算符): =
? By default, each data field of one object is copied to its counterpart in the other object.(默認(rèn)情況下,對(duì)象中的每個(gè)數(shù)據(jù)域都被拷貝到另一對(duì)象的對(duì)應(yīng)部分)

Example: circle2 = circle1;
? copies the radius in circle1 to circle2.
? After the copy, circle1 and circle2 are still two different objects, but with the sameradius.

Anonymous Object (匿名對(duì)象)
?Occasionally, you may create an object and use it only once. (有時(shí)需要?jiǎng)?chuàng)建一個(gè)只用一次的對(duì)象)
?In this case, you don’t have to name the object. (此時(shí),無(wú)需給對(duì)象命名)
Such objects are called anonymous objects. (這種對(duì)象叫做匿名對(duì)象)
?The syntax is

ClassName(); //using the no-arg
ClassName(arguements); //using the constructor with arguments
int main() {
    Circle circle1, circle2;
    circle1 = Circle();
    circle2 = Circle(5);
    cout << "Area is " << Circle().getArea() << endl;
    cout << "Area is " << Circle(5).getArea() << endl;
    return 0;
}

Section 4 : Separating Declaration from Implementation

第4節(jié):將聲明與實(shí)現(xiàn)分離

Separating Declaration from Implementation (聲明與實(shí)現(xiàn)分離)
C++ allows you to separate class declaration from implementation. (C++中,類聲明與實(shí)現(xiàn)可以分離)
? The class declaration describes the contract of the class (類聲明描述了類的約定)
? The class implementation implements the contract. (類實(shí)現(xiàn)則實(shí)現(xiàn)該約定)

.h: 類聲明
.cpp: 類實(shí)現(xiàn)
? FunctionType ClassName :: FunctionName (Arguments) { //… }

Inline Declaration & Inline Function (內(nèi)聯(lián)聲明與內(nèi)聯(lián)函數(shù))
?When a function is implemented inside a class declaration, it automatically
becomes an inline function. (當(dāng)函數(shù)在類聲明中實(shí)現(xiàn),它自動(dòng)成為內(nèi)聯(lián)函數(shù))

class A {
public:
    A() {
    // do something;
    }
    double f1() {
    // return a number
    }
    double f2();
    };
    double A::f2() {
    //do something
}

class A {
public:
    A() {
    // do something;
    }
    double f1() {
    // return a number
    }
    double f2();
    };
    inline double A::f2() {
    //do something
}

Section 5 : Object Pointer & Dynamic Object

第5節(jié):對(duì)象指針與動(dòng)態(tài)對(duì)象

Accessing Object Members via Pointers (用指針訪問對(duì)象成員)
?Object names cannot be changed once they are declared. (對(duì)象名聲明后無(wú)法修改)
?However, object pointers can be assigned new object names(對(duì)象指針可以指向新的對(duì)象名)

1. Circle circle1;
2. Circle *pCircle = &circle1;
3. cout << "The radius is " << (*pCircle).radius << endl;
4. cout << "The area is " << (*pCircle).getArea() << endl;
5. (*pCircle).radius = 5.5;
6. cout << "The radius is " << pCircle->radius << endl;
7. cout << "The area is " << pCircle->getArea() << endl;

Creating Dynamic Objects on Heap (在堆中創(chuàng)建對(duì)象)
?Object declared in a function is created in the stack.(在函數(shù)中聲明的對(duì)象都在棧上創(chuàng)建); When the function returns, the object is destroyed (函數(shù)返回,則對(duì)象被銷毀).
?To retain the object, you may create it dynamically on the heap using the newoperator. (為保留對(duì)象,你可以用new運(yùn)算符在堆上創(chuàng)建它)

ClassName *pObject = new ClassName(); //用無(wú)參構(gòu)造函數(shù)創(chuàng)建對(duì)象
Circle *pCircle1 = new Circle(); //用無(wú)參構(gòu)造函數(shù)創(chuàng)建對(duì)象
Circle *pCircle2 = new Circle(5.9); //用有參構(gòu)造函數(shù)創(chuàng)建對(duì)象
ClassName *pObject = new ClassName(arguments); //用有參構(gòu)造函數(shù)創(chuàng)建對(duì)象
//程序結(jié)束時(shí),動(dòng)態(tài)對(duì)象會(huì)被銷毀,或者
delete pObject; //用delete顯式銷毀

Section 6 : The C++ string Class

第6節(jié):C++字符串類

The C++ string Class
?C++ 使用 string 類處理
字符串
?string類中的函數(shù)

  1. 構(gòu)造
  2. 追加
  3. 賦值
  4. 位置與清除
  5. 長(zhǎng)度與容量
  6. 比較
  7. 子串
  8. 搜索
  9. 運(yùn)算符

注意事項(xiàng)
?操作string對(duì)象中的字符串內(nèi)容時(shí),有時(shí)會(huì)用到“index”。
"Welcome to C and C++!"
0號(hào)位置0號(hào)字符
從7號(hào)位置開始的5個(gè)字符“ to C”
第1個(gè)字符'W'
第8個(gè)字符' ' (空格)

很多string的函數(shù)接受兩個(gè)數(shù)字參數(shù): index, n
index: 從index號(hào)位置開始
n: 之后的n個(gè)字符

Constructing a String (創(chuàng)建 string 對(duì)象)
?Create an empty string using string’s no-arg constructor(用無(wú)參構(gòu)造函數(shù)創(chuàng)建一個(gè)空字串):
string newString;
?Create a string object from a string value or from an array of characters (由一個(gè)字符串常量或字符串?dāng)?shù)組創(chuàng)建string對(duì)象) :

string message("Aloha World!");
char charArray[] = {'H', 'e', 'l', 'l', 'o', '\0'};
string message1(charArray);

Appending a String (追加字符串)
?You can use several overloaded functions to add new contents to a string. (一系列的重載函數(shù)可以將新內(nèi)容附加到一個(gè)字符串中)

string s1("Welcome");
s1.append(" to C++"); // appends " to C++" to s1
cout << s1 << endl; // s1 now becomes Welcome to C++

string s2("Welcome");
s2.append(" to C and C++", 3, 2); // appends " C" to s2
cout << s2 << endl; // s2 now becomes Welcome C

string s3("Welcome");
s3.append(" to C and C++", 5); // appends " to C" to s3
cout << s3 << endl; // s3 now becomes Welcome to C

string s4("Welcome");
s4.append(4, 'G'); // appends "GGGG" to s4
cout << s4 << endl; // s4 now becomes WelcomeGGGG

Assigning a String (為字符串賦值)
?You can use several overloaded functions to assign new contents to a string(一系列的重載函數(shù)可以將一個(gè)字符串賦以新內(nèi)容)

string s1("Welcome");
s1.assign("Dallas"); // assigns "Dallas" to s1
cout << s1 << endl; // s1 now becomes Dallas

string s2("Welcome");
s2.assign("Dallas, Texas", 1, 3); // assigns "all" to s2
cout << s2 << endl; // s2 now becomes all

string s3("Welcome");
s3.assign("Dallas, Texas", 6); // assigns "Dallas" to s3
cout << s3 << endl; // s3 now becomes Dallas

string s4("Welcome");
s4.assign(4, 'G'); // assigns "GGGG" to s4
cout << s4 << endl; // s4 now becomes GGGG

Functions at, clear, erase, and empty
?at(index): 返回當(dāng)前字符串中index位置的字符
?clear(): 清空字符串
?erase(index, n): 刪除字符串從index開始的n個(gè)字符
?empty(): 檢測(cè)字符串是否為空

string s1("Welcome");
cout << s1.at(3) << endl; // s1.at(3) returns c
cout << s1.erase(2, 3) << endl; // s1 is now Weme
s1.clear(); // s1 is now empty
cout << s1.empty() << endl; // s1.empty returns 1 (means true)

Comparing Strings (比較字符串)
?compare() 函數(shù)用于比較兩個(gè)字符串。它與C語(yǔ)言中的 strcmp() 函數(shù)很像。

string s1("Welcome");
string s2("Welcomg");
cout << s1.compare(s2) << endl; // returns -2
cout << s2.compare(s1) << endl; // returns 2
cout << s1.compare("Welcome") << endl; // returns 0

Obtaining Substrings (獲取子串)
?at() 函數(shù)用于獲取一個(gè)單獨(dú)的字符;而substr() 函數(shù)則可以獲取一個(gè)子串

string s1("Welcome");
cout << s1.substr(0, 1) << endl; // returns W; 從0號(hào)位置開始的1個(gè)字符
cout << s1.substr(3) << endl; // returns come; 從3號(hào)位置直到末尾的子串
cout << s1.substr(3, 3) << endl; // returns com;從3號(hào)位置開始的3個(gè)字符

Searching in a String (搜索字符串)
?find() 函數(shù)可以在一個(gè)字符串中搜索一個(gè)子串或者一個(gè)字符

string s1("Welcome to HTML");
cout << s1.find("co") << endl; // returns 3; 返回子串出現(xiàn)的第一個(gè)位置
cout << s1.find("co", 6) << endl; // returns -1 從6號(hào)位置開始查找子串出現(xiàn)的第一個(gè)位置
cout << s1.find('o') << endl; // returns 4 返回字符出現(xiàn)的第一個(gè)位置
cout << s1.find('o', 6) << endl; // returns 9 從6號(hào)位置開始查找字符出現(xiàn)的第一個(gè)位置

Inserting and Replacing Strings (插入和替換字符串)
?insert() : 將某個(gè)字符/字符串插入到當(dāng)前字符串的某個(gè)位置
?replace() 將本字串從某個(gè)位置開始的一些字符替換為其它內(nèi)容

string s1("Welcome to HTML");
s1.insert(11, "C++ and ");
cout << s1 << endl; // s1 becomes Welcome to C++ and HTML

string s2("AA");
s2.insert(1, 4, 'B'); //在1號(hào)位置處連續(xù)插入4個(gè)相同字符
cout << s2 << endl; // s2 becomes to ABBBBA

string s3("Welcome to HTML");
s3.replace(11, 4, "C++"); //從11號(hào)位置開始向后的4個(gè)字符替換掉。注意'\0'
cout << s3 << endl; // returns Welcome to C++

**String Operators (字符串運(yùn)算符) **

string s1 = "ABC"; // The = operator
string s2 = s1; // The = operator
for (int i = s2.size() - 1; i >= 0; i--)
cout << s2[i]; // The [] operator

string s3 = s1 + "DEFG"; // The + operator
cout << s3 << endl; // s3 becomes ABCDEFG

s1 += "ABC";
cout << s1 << endl; // s1 becomes ABCABC

s1 = "ABC";
s2 = "ABE";
cout << (s1 == s2) << endl; // Displays 0
cout << (s1 != s2) << endl; // Displays 1
cout << (s1 > s2) << endl; // Displays 0
cout << (s1 >= s2) << endl; // Displays 0
cout << (s1 < s2) << endl; // Displays 1
cout << (s1 <= s2) << endl; // Displays 1 
Operator Description
[ ] 用數(shù)組下標(biāo)運(yùn)算符訪問字符串中的字符
= 將一個(gè)字符串的內(nèi)容復(fù)制到另一個(gè)字符串
+ 連接兩個(gè)字符串得到一個(gè)新串
+= 將一個(gè)字符串追加到另一個(gè)字符串末尾
<< 將一個(gè)字符串插入一個(gè)流
>> 從一個(gè)流提取一個(gè)字符串,分界符為空格或者空結(jié)束符
==, !=, <,<=, >, >= 用于字符串比較

Section 7 : Data Field Encapsulation

第7節(jié):數(shù)據(jù)域封裝

數(shù)據(jù)域采用public的形式有2個(gè)問題
? First, data may be tampered. (數(shù)據(jù)會(huì)被類外
的方法篡改)
? Second, it makes the class difficult to
maintain and vulnerable to bugs. (使得類難
于維護(hù),易出現(xiàn)bug)

Accessor and Mutator (訪問器與更改器)
To read/write private data, we need get/set function(為讀寫私有數(shù)據(jù),需要get/set函數(shù))
? get function is referred to as a getter (獲取器,or accessor),
? set function is referred to as a setter (設(shè)置器,or mutator).

Signature of get function (General form) (get函數(shù)的一般原型)
? returnType getPropertyName()

Signature of get function (Bool type) (布爾型get函數(shù)的原型)
? bool isPropertyName()

Signature of set function (set函數(shù)的原型)
? void setPropertyName(dataType propertyValue)

26. 布爾變量/函數(shù)的命名應(yīng)使用前綴“is”
There are a few alternatives to the is prefix
that fit better in some situations. These are the
has, can and should prefixes:
"is"前綴有時(shí)會(huì)有更好的替換,包括has, can和should
例如:bool hasLicense(); bool canEvaluate();
bool shouldSort();

Section 8 : The Scope of Variables & "this" pointer

第8節(jié):變量作用域與this指針

The Scope of Variables – Review (變量作用域-回顧)
C語(yǔ)言的“函數(shù)”章節(jié),介紹了3種變量作用域

Global variables (全局變量)
? are declared outside all functions and are accessible to all functions in its scope. (在所有函數(shù)外面聲明并在其作用域內(nèi)可被所有函數(shù)訪問)
? The scope starts from its declaration and continues to the end of the program. (作用域起于聲明,止于程序結(jié)束)

Local variables (局部變量)
? are defined inside functions. (在函數(shù)內(nèi)定義)
? The scope starts from its declaration and continues to the end of the block thatcontains the variable. (作用域起于聲明,止于包含該變量的塊尾)

Static local variables (靜態(tài)局部變量)
? permanently stored in the program.
? can be used in the next call of the function

The Scope of Data Fields in Class (類中數(shù)據(jù)域的作用域)
The data fields
? are declared as variables inside class (被定義為變量形式)
? are accessible to all constructors and functions in the class.(可被類內(nèi)所有函數(shù)訪問)

Data fields and functions can be declared in any order in a class. (數(shù)據(jù)域與函數(shù)可按任意順序聲明)

Hidden by same name (同名屏蔽)
If a local variable has the same name as a data field: (若成員函數(shù)中的局部變量與某數(shù)據(jù)域同名)
? the local variable takes precedence (局部變量?jī)?yōu)先級(jí)高)
? the data field with the same name is hidden. (同名數(shù)據(jù)域在函數(shù)中被屏蔽)

The this Pointer
?How do you reference a class’s hidden data field in a function? (如何在函數(shù)內(nèi)訪問類中被屏蔽的數(shù)據(jù)域)

this keyword
? a special built-in pointer (特殊的內(nèi)建指針)
? references to the calling object. (引用當(dāng)前函數(shù)的調(diào)
用對(duì)象)

class Circle {
public:
Circle();
Circle(double radius)
{
this->radius = radius;
}
private:
double radius;
public:
void setRadius(double);
//……
};

Screen類中有兩個(gè)函數(shù)move() 和 set(),如何設(shè)計(jì)這兩個(gè)函數(shù)的返回值,才能使得下面語(yǔ)句是合法的?
myScreen.move(4,0).set('#');

Simple way to avoid name hidden (避免重名屏蔽的簡(jiǎn)單方法)

class Circle {
public:
Circle();
Circle(double radius)
{
//this->radius = radius;
radius_ = radius;
}
private:
double radius_;
public:
void setRadius(double);
//……
};
11. Private class variables should have underscore suffix.
11. 私有類成員變量名應(yīng)有下劃線后綴
例:
class SomeClass {
private:
int length_;
}
代碼中容易區(qū)分類成員變量及函數(shù)局部變量
也有些規(guī)范中使用下劃線前綴。但使用后綴讓名字可
讀性更好

Section 9 : Passing Objects to Functions

第9節(jié):對(duì)象作為函數(shù)參數(shù)

Passing Objects to Functions (對(duì)象作為函數(shù)參數(shù))
?You can pass objects by value or by reference. (對(duì)象作為函數(shù)參數(shù),可以按值傳遞也可以按引用傳遞)

Section 10 : Array of Objects

第10節(jié):對(duì)象數(shù)組

Array of Objects (對(duì)象數(shù)組)
?聲明方式1
Circle circleArray[10];
Question:
circleArray[1].getRadius() 的值是
多少?
?聲明方式2
Circle circleArray[3] = {
Circle(3),
Circle(4),
Circle(5)
};

Section 11 : Class Abstration and Encapsulation

第11節(jié):類抽象與封裝

Class Abstraction and Encapsulation (類抽象與封裝)

Class abstraction (類抽象)
? to separate class implementation from the use of the class. (將類的實(shí)現(xiàn)與使用分離開)
? The creator provides a class description (類創(chuàng)建者提供類的描述)
? The user of the class does not need to know how the class is implemented. (使用者不需知道類是如何實(shí)現(xiàn)的)

Class encapsulation (類封裝)
? The detail of implementation is encapsulated and hidden from the user.(類實(shí)現(xiàn)的細(xì)節(jié)被封裝起來(lái),并對(duì)用戶是隱藏的)

Section 12 : Constructor Initializer Lists

第12節(jié):構(gòu)造函數(shù)初始化列表

Constructor Initializer (構(gòu)造函數(shù)初始化)
在構(gòu)造函數(shù)中用初始化列表初始化數(shù)據(jù)域

ClassName (parameterList)
: dataField1(value1), dataField2(value2)
{
// Something to do
}

Why we need a Constructor Initializer Lists? (為何需要初始化列表)
?If a data field is an object type (Object in Object) (若類的數(shù)據(jù)域是一個(gè)對(duì)象類型)

The Role of Default Constructor (默認(rèn)構(gòu)造函數(shù)的角色)
If a data field is an object type (Object in Object) (若類的數(shù)據(jù)域是一個(gè)對(duì)象
類型)
? the default constructor is automatically invoked to construct an object for the data field.(該對(duì)象的無(wú)參構(gòu)造函數(shù)會(huì)被自動(dòng)調(diào)用)
? If a default constructor does not exist, a compilation error will be reported. (若沒有無(wú)參構(gòu)造函數(shù),則編譯器報(bào)錯(cuò))

You can use the Constructor Initializer to construct the object manually (你也可以在初始化列表中手工構(gòu)造對(duì)象)

Unit05 - More on Objects and Classes

第5單元: 萬(wàn)類霜天競(jìng)自由 – 對(duì)象和類的更多內(nèi)容

Section 01 : Immutable Objects and Classes; Preventing Multiple Declaration

第01節(jié):不可變對(duì)象、不可變類;避免多次聲明

Immutable Objects and Classes
?immutable object(不可變對(duì)象): The contents of an object cannot be changed(except through memberwise copy) once the object is created.(對(duì)象創(chuàng)建后,其內(nèi)容不可改變,除非通過(guò)成員拷貝)
?immutable class (不可變類) : The class of immutable object (不可變對(duì)象所
屬的類)

Example
A class is NOT necessarily immutable even: (下述情況中,類也不一定是“不可變類”)
? with all private data fields (所有數(shù)據(jù)域均為私有屬性)
? no mutators. (無(wú)更改器函數(shù))

int main(){
Person person(111223333, 1970, 5, 3);
Date *pDate = person.getBirthDate();
pDate -> setYear(2010);
cout << "birth year after the change is " <<
person.getBirthDate() -> getYear() << endl;
return 0;
}
4. Variable names must be in mixed case starting with lower case.
4. 變量名必須混合大小寫且以小寫字母開頭
例如:line, savingsAccount

How to make a class immutable? (讓類成為“不可變類”)
? Mark all data fields private (所有數(shù)據(jù)域
均設(shè)置為“私有”屬性)
? No mutator functions (沒有更改器函數(shù))
? No accessor that would return a
reference/pointer to a mutable data field
object
(也沒有能夠返回可變數(shù)據(jù)域?qū)ο蟮囊?br> 或指針的訪問器)

Preventing Multiple Declarations (避免多次聲明)

  1. Put "#pragma once" in the first line of .h file (使用“雜注”)
    ? 依賴于編譯器
    ? 古老的編譯器不支持
  2. Use #ifndef preprocessing instructions in .h file (使用“宏”)
#ifndef FILENAME_H
#define FILENAME_H
// The contents of the header file
#endif FILENAME_H

Section 02 : Instance and Static Members

第02節(jié):實(shí)例成員與靜態(tài)成員

Rules for Static member function ? (使用靜態(tài)成員函數(shù)的規(guī)則)
?Rules1: How to invoke Static member function: (調(diào)用靜態(tài)成員函數(shù))
?Rules2: Static member functions access other members: (靜態(tài)成員函數(shù)訪問其他成員)

主調(diào)函數(shù)\被訪問 靜態(tài) 非靜態(tài)
靜態(tài) 通過(guò)類名/對(duì)象名 只能通過(guò)對(duì)象名
非靜態(tài) 只能通過(guò)對(duì)象名 ?

Static member: example

class A {
public:
A(int a=0){x=a;}
static void f1();
static void f2(A a);
private:
int x;
static int y;
};
void A::f2(A a)
{
cout<< y;
cout<< x; //Error
cout<< a.x; //OK通過(guò)對(duì)象訪問非靜態(tài)數(shù)據(jù)成員
}

void A::f1()
{
cout<<y<<endl;//可直接訪問靜態(tài)數(shù)據(jù)成員
}
void main ()
{
A::f1();//通過(guò)類名調(diào)用靜態(tài)成員函數(shù)
A mA(3);
A::f2(mA);//通過(guò)類名調(diào)用靜態(tài)成員函數(shù)
mA.f1();//通過(guò)對(duì)象調(diào)用靜態(tài)成員函數(shù)
}

Use Class Name (for readablity) (使用類名訪問靜態(tài)變量/函數(shù))
? Use ClassName::functionName(arguments) to invoke a static function and ClassName::staticVariable.

class A {
public:
    A(int a=0){x=a;}
    static void f1();
    static void f2(A
    a);
private:
    int x;
    static int y;
};
void A::f2(A a){
    cout<< A::y;
    cout<< a.x;
}
void A::f1() {
    cout<<A::y<<endl;
}
void main
    (){
    A::f1();
    A mA(3);
    A::f2(mA);
    mA.A::f1();
}

Instance or Static? (實(shí)例還是靜態(tài))
When to use STATIC in class? (何時(shí)在類中使用靜態(tài)成員)
? A variable or function that is not dependent on a specific instance of the class should be a static variable or function. (變量和函數(shù)不依賴于類的實(shí)例時(shí))
For example
? every circle has its own radius. Radius is dependent on a specific circle. Therefore, radius is an instance variable of the Circle class. Since the getArea function is dependent on a specific circle, it is an instance function.
? Since numberOfObjects is not dependent on any specific instance, it should be declared static.

Section 03 : Destructor and Friend

第03節(jié):析構(gòu)函數(shù)與友元

Destructors (析構(gòu)函數(shù))
?Destructors are the opposite of constructors. (dtor vs ctor)

-- Destructor Constructor
When to invoke(何時(shí)調(diào)用) when the object is destroyed when an object is created
Prototype(原型) C::~C( ) C::C(arguments)
Default prototype(默認(rèn)函數(shù)的原型) C::~C( ) C::C( )
What if no explicit decl? (沒有顯式聲明怎么辦) Compiler will create a default one (編譯器會(huì)生成默認(rèn)函數(shù))
Overloadable(可否重載) No, only 1 Yes

Why Friend (為何需要友元)
?Private members: CANNOT be
accessed from outside of the class.
(私有成員無(wú)法從類外訪問)

Circle c1();
c1.radius = 1;

?Occasionally, it is convenient to
allow some trusted functions and
classes to access a class’s private
members. (但有時(shí)又需要授權(quán)某些
可信的函數(shù)和類訪問這些私有成
員)

Friend functions and classes (友元函數(shù)和友元類)
?C++ enables you to use the friend
keyword to declare friend functions
and friend classes for a class (用
friend關(guān)鍵字聲明友元函數(shù)或者友
元類)
?Disadvantage of "friend": break the
encapsulation

Section 04 : Copy Constructor

第04節(jié):拷貝構(gòu)造函數(shù)

Copy Constructors
?Every class has a copy constructor.

ClassName (ClassName&); 類的對(duì)象的引用
Circle (Circle&);
Circle (const Circle&);

?Default copy ctor
? simply copies each data field in one
object to its counterpart in the other
object. (默認(rèn)copy ctor簡(jiǎn)單地將參數(shù)對(duì)
象中的每個(gè)數(shù)據(jù)域復(fù)制到新建對(duì)象中)

class X { //C++03/11: 12.8
// ...
public:
X(int);
X(const X&, int = 1);
};
X a(1); // calls X(int);
X b(a, 0); // calls X(const X&, int);
X c = b; // calls X(const X&, int);

Shallow Copy vs. Deep Copy (淺拷貝和深拷貝)
?Shallow copy: if the field is a pointer to some object, the address of the
pointer is copied rather than its contents. (拷指針,而非指針指向的內(nèi)容)
?Deep copy: Copy the contents that pointed by the pointer (拷指針指向的內(nèi)容)

Shallow Copy 1 ? (淺拷貝1)
?Before person2 is copied to person1, the birthDate field of person1 and
person2 point to two different Date objects. (person2拷貝到person1之前,他
們的birthDate指向不同的Date對(duì)象)

Shallow Copy 2 ?(淺拷貝2)
?After person2 is copied to person1, the birthDate field of person1 and person2
point to the same Date object. (person2拷貝給person1后,他們的birthDate都
指向同一個(gè)Date對(duì)象)

Customizing Copy Constructor(定制拷貝構(gòu)造函數(shù))
Shallow copy:
? default copy constructor (默認(rèn)構(gòu)造函
數(shù))
? assignment operator for copying = (用
于拷貝對(duì)象的賦值運(yùn)算符)
Deep copy: you should implement
the copy ctor. (自行編寫拷貝構(gòu)造
函數(shù))

class X {
// ...
};
X a; // calls X();
X b(a); // calls X(const X&, int);
X c = b; // calls X(const X&, int);
a = c; // calls X& operator= (const X&);

Section 05 : Case Study

第05節(jié):示例分析

Case study1: The Course Class

Course
-name: string//The name of the course. (課程名稱)
-students: string[100]//The students who take the course.(選課學(xué)生)
-numberOfStudents: int//The number of students (default: 0).(學(xué)生數(shù)量,默認(rèn)為0)
+Course(name: &string)//Creates a Course with the specified name.(用制定名字創(chuàng)建課程)
+getName(): string//Returns the course name. (返回課程名)
+addStudent(student: &string): void//
Adds a new student to the course list. (增加一個(gè)選課學(xué)生)
+getStudents(): string*//Returns the array of students for the course. (返回所有選課學(xué)生)
+getNumberOfStudents(): int//Returns the number of students for the course.(返回選課學(xué)生數(shù)量)
```
Case study 2: The StackOfInteger Class
A stack is a data structure that holds
objects in a last-in first-out
fashion.(棧:后進(jìn)先出)
Stack applications:
? 函數(shù)調(diào)用時(shí),主函數(shù)傳給子函數(shù)的參
數(shù)先進(jìn)棧,進(jìn)入子函數(shù)后,子函數(shù)的
局部變量也按序在棧中建立
? 子函數(shù)返回時(shí),局部變量出棧、參數(shù)
出棧。

Members of Stack (stack類的成員)
?The StackOfIntegers class encapsulates the stack storage and provides the
operations for manipulating the stack. (stack類封裝了棧的存儲(chǔ)空間并提供
了操作棧的函數(shù))

### Section 06 : The C++ vector Class
### 第06節(jié):vector 類
The C++ vector Class
?Limitation of using array to store values: the array size is fixed in the class
declaration. (用數(shù)組存放數(shù)據(jù)時(shí),容量大小不可變)
?The vector object can increase its size if needed.(vector對(duì)象容量可自動(dòng)增大)
Examples


```
vector<int> intVector;
// Store numbers 1, ..., 10 to the vector
for (int i = 1; i < 10; i++)
intVector.push_back(i + 1);

25. Iterator variables should be called i, j, k etc.
25. 迭代變量名應(yīng)該用 i, j, k 等
此外,變量名 j, k應(yīng)只被用于嵌套循環(huán)
盡量多用i做循環(huán)變量;
盡量令i的作用域限制在循環(huán)塊內(nèi)
```
### Section 07 : More Programming Style Guidelines
### 第07節(jié):更多編碼規(guī)范
```
Two basic guidelines (兩個(gè)最基礎(chǔ)的規(guī)范)
1. Any violation to the guide is allowed if it enhances readability.
1. 只要能增強(qiáng)可讀性,你在編碼時(shí)可以不遵守這些編程風(fēng)格指南
一語(yǔ)道盡規(guī)范的目的
2. The rules can be violated if there are strong personal objections against them.
2. 如果你有很好的個(gè)人理由的話,可以不遵守這些規(guī)范

Why do I violate the rules? (為嘛我要違反規(guī)則)
46. Variables should be initialized where they are declared.
46.變量應(yīng)在其聲明處初始化
int x = 1;
int x1 = 1;
int x2 = 1;
// blah blah blah
int x = 8;
請(qǐng)
在
函
數(shù)
開
頭
定
義
變
量
71. Basic indentation should be 2.
Indentation of 1 is too small to emphasize the
logical layout of the code. Indentation larger than 4
makes deeply nested code difficult to read and
increases the chance that the lines must be split.
Choosing between indentation of 2, 3 and 4, 2 and 4
are the more common, and 2 chosen to reduce the
chance of splitting code lines.

73. The class declarations should have the following form:
class SomeClass : public BaseClass
{
public://編輯器/開發(fā)環(huán)境有關(guān)
...
protected:
...
private:
...
}

```

```
Layouts for loop statements (循環(huán)語(yǔ)句的布局)
76. A for statement should have the following form:
for (initialization; condition; update) {
statements;
}
77. An empty for statement should have the following form:
for (initialization; condition; update)
;
This emphasizes the fact that the for statement is empty and it
makes it obvious for the reader that this is intentional. Empty
loops should be avoided however.
78. A while statement should have the following form:
while (condition) {
statements;
}
79. A do-while statement should have the following form:
do {
statements;
} while (condition);
74. Method definitions should have the following form:
74. 方法定義應(yīng)遵循如下形式
void someMethod()
{
...
}
```

About white space (關(guān)于空格)
```
84.
‐ Conventional operators should be surrounded by a space character. (運(yùn)算符前后應(yīng)有空格)
‐ C++ reserved words should be followed by a white space.(C++保留字后邊應(yīng)有空格)
‐ Commas should be followed by a white space. (逗號(hào)后面跟空格)
‐ Colons should be surrounded by white space.(冒號(hào)前后有空格)
‐ Semicolons in for statments should be followed by a space character.(for語(yǔ)句的分號(hào)后有空格)
例如:
a = (b + c) * d; // NOT: a=(b+c)*d
while (true) // NOT: while(true)
{
...
doSomething(a, b, c, d); // NOT: doSomething(a,b,c,d);
case 100 : // NOT: case 100:
for (i = 0; i < 10; i++) { // NOT: for(i=0;i<10;i++){
...
```

### Section 01 : Inheritance
### 第01節(jié):繼承
回顧
?面向?qū)ο蟮?個(gè)特點(diǎn):
? A(抽象) P(多態(tài))I(繼承)E(封裝)
?前兩個(gè)單元:AE
?本單元: PI

Inheritance (繼承)
?巴巴家族的能力
?自行車的例子

Example: GeometricObject (幾何對(duì)象)
幾何對(duì)象
矩形 圓
形
……
派生類與基類之間是一種________關(guān)系
正確答案:is-a

類B繼承類A,代碼可以寫作:
class B: A {
//Some data field and function
};
正確答案: B.×

### Section 02 : Constructor and Destructor
### 第02節(jié):構(gòu)造函數(shù)和析構(gòu)函數(shù)
派生類繼承的成員
派生類繼承 ctor 和 dtor 嗎?
派生類不繼承的特殊函數(shù)
? 構(gòu)造函數(shù) (C++11已允許繼承)
? 析構(gòu)函數(shù)
? 作為特權(quán)地位的友元函數(shù)
? 賦值運(yùn)算符函數(shù)
```
struct A {
A(int i) {}
A(double d, int i) {}
// ...
};
struct B : A {
using A::A; // 繼承基類構(gòu)造函數(shù)
int d{0}; // 新的變量初始化方法
};
int main() {
B b(1); // b.d 初始化為 0
}
```

Calling Base Class Constructors (調(diào)用基類構(gòu)造函數(shù))
?Ctors of base class can only be invoked from the constructors of the derived classes. (基類構(gòu)造函數(shù)只能由派生類構(gòu)造函數(shù)調(diào)用)
?The syntax to invoke it is as follows:
```
DerivedClass(parameterList) : BaseClass() {
// Perform initialization
}
// Or
DerivedClass(parameterList) : BaseClass(argumentList) {
// Perform initialization
}
```

No-Arg Constructor in Base Class(基類的無(wú)參構(gòu)造函數(shù))
Rules for invoke constructors in derived class
? A constructor in a derived class must always invoke a constructor in its base class. (派生類構(gòu)造函數(shù)必須調(diào)用基類構(gòu)造函數(shù))
? If a base constructor is not invoked explicitly, the base class’s no-arg constructor is invoked by default. (若基類ctor未被顯式調(diào)用,基類的無(wú)參構(gòu)造函數(shù)就會(huì)被調(diào)用)

Constructor and Destructor Chaining (構(gòu)造和析構(gòu)函數(shù)鏈)
constructor chaining (構(gòu)造函數(shù)鏈)
? Constructing an instance of a class
invokes all the base class along the
inheritance chain. (構(gòu)造類實(shí)例會(huì)沿著
繼承鏈調(diào)用所有的基類ctor)
? Invoke sequence: base first, derive next
destructor chaining (析構(gòu)函數(shù)鏈)
? Conversely, the destructors are
automatically invoked in reverse
order(dtor與ctor正好相反)
? Invoke sequence: derive first, base next

no-arg constructor (無(wú)參構(gòu)造函數(shù))
?If a class is designed to be extended, provide a no-arg constructor. (若你的類想被別人擴(kuò)展,那么就提供一個(gè)無(wú)參構(gòu)造函數(shù))
```
#include <string>
class Fruit {
public:
Fruit(int id) {//A no-arg ctor is expected
}
std::string s;
};
class Apple: public Fruit {
public:
Apple() {//Apple() : Fruit() {}
}
};
int main () {
Apple apple;
}
```

```
34. 文件擴(kuò)展名:頭文件用.h,源文件用 .cpp (c++, cc也可)
35. A class should be declared in a header file and defined in a
source file where the name of the files match the name of the class.
35. 類應(yīng)該在頭文件中聲明并在源文件中定義,倆文件名字應(yīng)
該與類名相同
例如:MyClass.h, MyClass.c++
例外的是,模板類的聲明和定義都要放在頭文件中
49. Class variables should never be declared public.
49. 類成員變量不可被聲明為public
說(shuō)明:公有變量違背了C++的信息隱藏原則。例外的是,
如果class只是一個(gè)數(shù)據(jù)結(jié)構(gòu),類似C語(yǔ)言中的struct,則
可將類變量聲明為公有
```

1派生類中不能繼承基類中的


B.析構(gòu)函數(shù)

C.友元函數(shù)

D.賦值運(yùn)算符函數(shù)


2
基類的構(gòu)造函數(shù)能夠由派生類中的任何函數(shù)調(diào)用
×

3
類A的析構(gòu)函數(shù)在類外部定義時(shí)可以寫為如下形式:
~A::A() {
  //do something
}×
4
構(gòu)造函數(shù)和析構(gòu)函數(shù)是自動(dòng)調(diào)用的√

### Section 03 : Redefining Functions
### 第03節(jié):函數(shù)重定義

Redefining Functions
?GeometricObject::toString()
function returns a string describe the
GeometricObject. (該函數(shù)返回一個(gè)
字符串用于描述對(duì)象)
? You can redefine toString() in
Circle and Rectangle to return a
string descrie Circle or Rectangle
object. (你可以重定義派生類的該
函數(shù)以描述派生類對(duì)象)

```
string GeometricObject::toString() {
return "Geometric object color " + color +
" filled " + ((filled) ? "true" : "false");
}
string Circle::toString() {
return "Circle object color " + color +
" filled " + ((filled) ? "true" : "false");
}
string Rectangle::toString() {
return "This is a rectangle object");
}
```
Redefine (hide) (重定義/隱藏)
```
class GeometricObject{
public:
string toString () { return "parent";}
};
class Circle: public GeometricObject {
public:
string toString () { return "child";}
void g () { cout<<toString(); }
};
int main( ) {
Circle circle;
cout << circle.toString ();
circle.GeometricObject::toString ();
return 0;
}
```
Redefine v.s. Overload (重定義與重載)

Overload Functions (§5.7) (重載函數(shù))
? more than one function with the same name (多個(gè)函數(shù)名字相同)
? But different in at least one of the signatures: (但至少一個(gè)特征不同)
? parameter type (參數(shù)類型)
? parameter number (參數(shù)數(shù)量)
? parameter sequence (參數(shù)順序)

Redefine Functions (重定義函數(shù))
? The functions have the same signature (函數(shù)特征相同)
? Name (同名)
? Parameters (including type, number and sequence) (同參數(shù):類型,數(shù)量和順序)
? Return type (返回值類型)
? Defined in base class and derived class, respectively (在基類和派生類中分別定義)

### Section 04 : Polymorphism and Virtual Functions
### 第04節(jié):多態(tài)和虛函數(shù)
What is Polymorphism?
?廣義的多態(tài):不同對(duì)象對(duì)于相同的消息有不同的響應(yīng),就是OOP中的多
態(tài)性。
?截止目前:多態(tài)性有兩種表現(xiàn)的方式
重載:
class C {
public:
int f(int x);
int f( );
};

重定義:不同的對(duì)象調(diào)用重定義
函數(shù),表現(xiàn)出不同的行為
class A { int f() {return 1;} };
class B: public A
{ int f() {return 8;} };
A x; B y;
x.f();
y.f();

**Binding**
聯(lián)編(Binding): 確定具有多態(tài)性的
語(yǔ)句調(diào)用哪個(gè)函數(shù)的過(guò)程。

Static Binding (靜態(tài)聯(lián)編)
? 在程序編譯時(shí)確定調(diào)用哪個(gè)函數(shù)
? 例:函數(shù)重載

Dynamic Binding (動(dòng)態(tài)聯(lián)編)
? 在程序運(yùn)行時(shí),才能夠確定調(diào)用哪個(gè)
函數(shù)
? 用動(dòng)態(tài)聯(lián)編實(shí)現(xiàn)的多態(tài),也稱為運(yùn)行
時(shí)的多態(tài)。

Why Run-time Polymorphism
?Example: Why we need
run-time polymorphism?
(運(yùn)行時(shí)多態(tài)的必要性).

How do we implement polymorphism (如何實(shí)現(xiàn)多態(tài))
?virtual function (虛函數(shù))
?Override (覆蓋) : redefining a
virtual function in a derived class.
(在派生類中重定義一個(gè)虛函數(shù))

Polymorphism: using dynamic binding (動(dòng)態(tài)聯(lián)編)
How to enable dynamic
binding? (如何使得函數(shù)能夠
實(shí)現(xiàn)動(dòng)態(tài)聯(lián)編)
? The function must be declared
virtual in the base class. (基類同
名虛函數(shù))
? The variable that references the
object for the function must
contain the address of the object.
(訪問對(duì)象的成員函數(shù)時(shí),要用
指向?qū)ο蟮闹羔樆蛘邔?duì)象引用) 
```
class C {
public:
virtual string toString() {
return "class C";
}
};

void displayObject(C *p){
// cout << p->toString().data() << endl;
cout << p->toString().c_str() << endl;
}

int main(){
A a = A(); B b = B(); C c = C();
displayObject(&a);
displayObject(&b);
displayObject(&c);
return 0;
}
```
Note

If a function is defined virtual in a
base class, it is automatically virtual
in all its derived classes. (基類定義
了虛同名函數(shù),那么派生類中的
同名函數(shù)自動(dòng)變?yōu)樘摵瘮?shù))

Virtual functions:
? Virtual function table (虛函數(shù)表)
? Run-time binding (運(yùn)行時(shí)聯(lián)編)
? More overhead in run-time than nonvirtual
function (開銷大)
```
class C {
public:
virtual string toString() {
return "class C";
}
};
class B: public C{
string toString() {
return "class B";
}
};
class A: public B{
string toString() {
return "class A";
}
};
```
Summary: static binding v.s. dynamic binding
基類與派生類中有同名函數(shù)
1. 通過(guò)派生類對(duì)象訪問同名函數(shù)
? 靜態(tài)聯(lián)編
2. 通過(guò)基類對(duì)象的指針訪問同名函數(shù)
? 靜態(tài)聯(lián)編
3. 通過(guò)基類對(duì)象的指針訪問同名虛函數(shù)
? 動(dòng)態(tài)聯(lián)編

Summary: 靜態(tài)聯(lián)編的簡(jiǎn)單示例
```
class B { public: f(){…}};
class P: public B { public: f(){…}};
class Q: public B { public: f(){…}};
main () {
P p; Q q;
p.f();調(diào)用的是P::f()
q.f();調(diào)用的是Q::f()
}
```
```
Summary: 通過(guò)基類指針訪問同名函數(shù)的簡(jiǎn)單示例
class B { public: f(){…} };
class P: public B { public: f(){…} };
class Q: public B { public: f(){…} };
main () {
B* b_ptr; P p; Q q;
b_ptr=&p;
b_ptr->f();調(diào)用的是B::f()
b_ptr=&q;
b_ptr->f();調(diào)用的是B::f()
}
```
Summary: 動(dòng)態(tài)聯(lián)編的簡(jiǎn)單示例-指針形式
```
class B { public: virtual f() {} };
class P: public B { public: f() {} };
class Q: public B { public: f() {} };
main () {
B* b_ptr; P p; Q q;
b_ptr=&p;
b_ptr->f();調(diào)用的是P::f()
b_ptr=&q;
b_ptr->f();調(diào)用的是Q::f()
}
```

Summary:動(dòng)態(tài)聯(lián)編的簡(jiǎn)單示例-引用形式

```
class B { public: virtual f() {} };
class P: public B { public: f() {} };
class Q: public B { public: f() {} };
main () {
P p; Q q;
B& b_ptr1=p;
b_ptr1.f();調(diào)用的是P::f()
B& b_ptr2=q;
b_ptr2.f();調(diào)用的是Q::f()
}
```
### Section 05 : Accessibility (Visibility)
### 第05節(jié):訪問控制 (可見性控制)
The protected Keyword

the private and public keywords
? to specify whether data fields and functions can be accessed from the outside of the
class. (說(shuō)明數(shù)據(jù)及函數(shù)是否可以從類外面訪問)
? Private members can only be accessed from the inside of the class (私有成員只能在類
內(nèi)的函數(shù)訪問)
? Public members can be accessed from any other classes. (公有成員可被任何其他類訪
問)

A protected data field or a protected function in a base class can be accessed
by name in its derived classes. (保護(hù)屬性的數(shù)據(jù)或函數(shù)可被派生類成員訪
問)

訪問屬性示例
```
#include <iostream>
using namespace std;
class B {
public:
int i;
protected:
int j;
private:
int k;
};

class A: public B {
public:
void display() {
cout << i << endl; // Fine, cannot access it
cout << j << endl; // Fine, cannot access it
cout << k << endl; // Wrong, cannot access it
}
};

int main() {
A a;
cout << a.i << endl; // Fine, cannot access it
cout << a.j << endl; // Wrong, cannot access it
cout << a.k << endl; // Wrong, cannot access it
return 0;
}
```


1. 公有繼承
?公有繼承的派生類定義形式:
class 派生類名:public 基類名{
派生類新成員定義;
};

```
1. 基類成員 在派生類中的訪問屬性不變。
2. 派生類的成員函數(shù) 可以訪問基類的公有成員和保護(hù)成員,不能
訪問基類的私有成員;
3. 派生類以外的其它函數(shù) 可以通過(guò)派生類的對(duì)象,訪問從基類繼
承的公有成員, 但不能訪問從基類繼承的保護(hù)成員和私有成員。
```

2. 私有繼承
?私有繼承的派生類定義形式:
class 派生類名:private 基類名{
派生類新成員定義;
}; 

```
1. 基類成員 在派生類中的訪問屬性都變成 private。
2. 派生類的成員函數(shù) 可以訪問基類的公有成員和保護(hù)成員,不能
訪問基類的私有成員;
3. 派生類以外的其它函數(shù) 不能通過(guò)派生類的對(duì)象,訪問從基類繼
承的任何成員。
```

3. 保護(hù)繼承
?私有繼承的派生類定義形式:
class 派生類名:protected 基類名{
派生類新成員定義;
}; 

```
1. 基類成員 公有成員和保護(hù)成員在派生類中變成保護(hù)類型的,基類
的私有成員屬性不變。
2. 派生類的成員函數(shù) 可以訪問基類的公有成員和保護(hù)成員,不能
訪問基類的私有成員;
3. 派生類以外的其它函數(shù) 不能通過(guò)派生類的對(duì)象,訪問從基類繼
承的任何成員。
```

### Section 06 : Abstract Class and Pure Virtual Function
### 第06節(jié):抽象類與純虛函數(shù)

Abstract Classes (抽象類)
? classes become more specific &
concrete with each new derived class.
(派生類時(shí),新類會(huì)越來(lái)越明確和具
體)
? move back up to the parent and
ancestor , the classes become more
general and less specific. (沿著派生類
向父類移動(dòng),類會(huì)越來(lái)越一般化和
抽象)

 Sometimes a base class is so abstract that it cannot
have any specific instances. Such a class is referred
to as an abstract class (類太抽象以至于無(wú)法實(shí)例
化就叫做抽象類)

Abstract Functions (抽象函數(shù))
All geometric objects have: areas & perimeters
? Declare getArea() and getPerimeter() in GeometricObject class? (在幾何對(duì)象類中聲明
計(jì)算面積和周長(zhǎng)的函數(shù)?)
Is it meaningful for getArea() in GeometricObject ? (這種聲明有實(shí)際意義
嗎?)
? NO, the implementation is dependent on the specific type of geometric object.
? virtual double getArea() = 0;
? virtual double getPerimeter() = 0;
Such functions are referred to as abstract functions.
Abstract class: the class which contains abstract functions

### Section 07 : Dynamic Cast
### 第07節(jié):動(dòng)態(tài)類型轉(zhuǎn)換

Dynamic Casting – Why (為何需要?jiǎng)討B(tài)類型轉(zhuǎn)換)
```
void displayGeometricObject(GeometricObject &object)
{
cout << "The area is " << object.getArea() << endl;
cout << "The perimeter is " << object.getPerimeter() << endl;
}
```
 Suppose you wish to modify this function to display radius, diameter, area, and perimeter if the object is a circle. How can this be done? (怎么才能讓這個(gè)函數(shù)顯示圓對(duì)象的半徑、直徑面積和周長(zhǎng))

Dynamic Casting Example
dynamic_cast operator
? cast a parameter of the
GeometricObject type
into a Circle type (將基
類類型參數(shù)轉(zhuǎn)換為派
生類類型)
? then invoke the
getRadius() and
getDiameter() functions
defined in the Circle
class (然后調(diào)用派生類
中獨(dú)有的函數(shù))
```
// A function for displaying a geometric object
void displayGeometricObject(GeometricObject &object)
{
cout << "The area is " << object.getArea() << endl;
cout << "The perimeter is " << object.getPerimeter() << endl;
GeometricObject *p = &object;
Circle *p1 = dynamic_cast<Circle*>(p);
if (p1 != 0)
{
cout << "The radius is " << p1->getRadius() << endl;
cout << "The diameter is " << p1->getDiameter() << endl;
}
}
```
Upcasting and Downcasting (向上/向下 轉(zhuǎn)型)
?upcasting : Assigning a pointer of a derived class type to a pointer of its base
class type (將派生類類型指針賦值給基類類型指針)
?downcasting : Assigning a pointer of a base class type to a pointer of its
derived class type. (將基類類型指針賦值給派生類類型指針)

Upcasting and Downcasting (向上/向下 轉(zhuǎn)型 續(xù))
? Upcasting can be performed implicitly without using the dynamic_cast
operator. (上轉(zhuǎn)可不適用dynamic_cast而隱式轉(zhuǎn)換)
GeometricObject *g = new Circle(1);
Circle *c = new Circle(2);
g = c; //Correct

? However, downcasting must be performed explicitly. (下轉(zhuǎn)必須顯式執(zhí)行)
For example, to assign p to p1, you have to use
c = dynamic_cast<Circle *>(g);

typeid operator (typeid運(yùn)算符)
?How to obtain the information about the class of the object? (如何獲取對(duì)象所屬的類的信息)
?typeid operator: return a reference to an object of class type_info. (typeid運(yùn)算符返回一個(gè)type_info對(duì)象的引用)
?to display the class name for object x. (顯示對(duì)象x的類名)
string x;
cout << typeid(x).name() << endl;

基類對(duì)象和派生類對(duì)象的互操作
問題1:對(duì)象內(nèi)存布局
GeometricObject G; Circle C;
GeometricObject* pG=&G;
Circle* pC=&C;
問題2:互操作
G=C; //Y
C=G; //N
pG=&C; //Y
pC=&G; //N
GeometricObject &rG=C; //Y
Circle &rC=G; //N

? Warning ?
1. 可將派生類對(duì)象截?cái)?,只使用繼承來(lái)的信息
2. 但不能將基類對(duì)象加長(zhǎng),無(wú)中生有變出派生類對(duì)象
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容