C++ Primer Plus 6th代码阅读笔记
-
第一章没什么代码 -
第二章代码
- carrots.cpp :
- cout 可以拼接输出,cin.get()接受输入
- convert.cpp
- 函数原型放在主函数前,int stonetolb(int); 1 stone = 14 pounds 一英石等于十四英镑
- cin.get( )会读取输入字符,包括回车
- ourfunc.cpp
- using namespace std会在作用域里其作用,所以写在函数内的话,函数外不起作用
- 两次cin >>count,正常运行,说明cin >>(int或char)接受非空格,函数重载
- 对比cin.get()接受空格
- 若先cin >>(int或char)再cin.get(),且输入为a和回车,回车会被cin.get()截得
-
第三章代码
- arith.cpp
- cout.setf(ios_base::fixed, ios_base::floatfield);
- 第一个参数:fmtflags:bool,decimal-integer,hexadecimal-integer,floating
- 第二个参数:scientific|fixed:floatfield
- 通常cout会删除结尾的零。例如,将3333333.250000显示为3333333.25。调用cout.setf( )将覆盖这种行为,至少在新的实现中是这样的。
- fixed:定点表示法
- floatfield:科学定点
- 如果cin >> hats; cin >> heads;cin.get(); == cin >> hats; cin.get(); cin >> heads;cin.get();
- assign.cpp
- 浮点数强制转为整数:直接去掉小数点后的
- \a表示振铃
- \b表示退格
- devide.cpp
- 浮点常量默认为double
- 1.e7是double,1.e7f是float
- 对于long double类型,可使用l或L后缀(由于l看起来像数字1,因此L是更好的选择)
- short int 2bytes -32768 to 32767
- int 4bytes -2147483648 to 2147483647
- float 4bytes:大概也是10位,小数点后6位,不太清楚
- double 8bytes,小数点后15位,不太清楚
- 可以直接用INT_MAX来查,sizeof (int),sizeof 变量名
- 所以int默认是有符号的int
- fltadd.cpp
- 程序将数字加1,然后减去原来的数字。结果应该为1,但是结果为0。问题在于,2.34E+22是一个小数点左边有23位的数字。加上1,就是在第23位加1。但float类型只能表示数字中的前6位或前7位,因此修改第23位对这个值不会有任何影响。
- hexoct1.cpp
- 0x42十六进制 042八进制
- cout默认以十进制输出
- hexoct1.cpp
- modulus.cpp
- morechar.cpp
- typecast.cpp
- static_cast<>可用于将值从一种数值类型转换为另一种数值类型。
- 运算符static_cast<>比传统强制类型转换更严格
- 可能会更安全
-
第四章代码
-
addpntrs.cpp
- 数组头指针,直接数组名或者&数组名[0]
- stacks[1] 等价于 *(stacks + 1)
- sizeof(数组名) = 整个数组的大小,单位是字节,如果长度为10,int数组,10*4 = 40
- sizeof(pw) 指针的大小都是8个字节(对于64位系统),不管是double指针和int指针
-
arraynew.cpp
- double * p3 = new double [3]; // space for 3 doubles
- 定义指针指向开辟的内存
- delete [] p3;
-
arrsruct.cpp
-
结构体定义 -
定义完结构体,再定义结构体数组 -
结构体有点像int类型,是一种类型 -
结构体数组的定义及初始化 -
guests[0].volume来得到该… -
代码 -
inflatable guests[2] = // initializing an array of structs
{
{"Bambi", 0.5, 21.99}, // first structure in array
{"Godzilla", 2000, 565.99} // next structure in array
};
-
choices.cpp
- double a1[4] = {1.2, 2.4, 3.6, 4.8};
- vector a2(4);
- a2[0] = 1.0/3.0;
- a2[1] = 1.0/5.0;
- a2[2] = 1.0/7.0;
- a2[3] = 1.0/9.0;
- array<double, 4> a3 = {3.14, 2.72, 1.62, 1.41};
- 索引-2是什么意思呢:找到a1指向的地方,向前移两个double元素,并将20.2存储到目的地。也就是说,将信息存储到数组的外面。与C语言一样,C++也不检查这种超界错误。这表明数组的行为是不安全的。
-
delete.cpp
- 三种存储方式:自动存储,静态存储,动态存储。
- 自动存储
- 它们在所属的函数被调用时自动产生,在该函数结束时消亡
- 实际上,自动变量是一个局部变量,其作用域为包含它的代码块。代码块是被包含在花括号中的一段代码。
- 自动变量通常存储在栈中
- 静态存储
- static double fee = 56.60
- 存在于程序的整个生命周期
- 动态存储
- new和delete运算符
- 自由存储空间(free store)或堆(heap)
- 程序员对程序如何使用内存有更大的控制权
- 自动添加和删除机制使得占用的内存总是连续的,但new和delete的相互影响可能导致占用的自由存储区不连续,这使得跟踪新分配内存的位置更困难。
- 如果使用new后不使用delete,会导致内存泄漏,该内存无法收回
- C++智能指针有助于自动完成这种任务
-
instr1/2/3.cpp
- 都是输入给char name[ArSize];而不是char * name;
- char name[Arsize];
- cin>>name;//不接受回车,空格,但是当输入“dec liu”时,会被看成两次输入
- cin使用空白(空格、制表符和换行符)来确定字符串的结束位置,这意味着cin在
获取字符数组输入时只读取一个单词。读取该单词后,cin将该字符串放到数组中,并自动在结尾添加空字符。 - cin.getline(name,Arsize);//接受回车,空格
- getline( )函数每次读取一行。它通过换行符来确定行尾,但不保存换行符。相反,
在存储字符串时,它用空字符来替换换行符,空字符即字符串末尾。 - 此时输入“dec liu”就正常
- cin.get(name, ArSize).get();
- get并不再读取并丢弃换行符,而是将其留在输入队列中
- get()可以知道读取停止是因为已经读取了整行还是由于数组已填满呢
- cin.getline()和cin.get()都有空行问题,读取到空行,会设置失效位,接着输入被阻断,但可以用cin.clear(),来继续输入。
- 总结:
- 第一种:怕长度长的,怕有空格的输入,会导致一次输入变成来两次输入
- 第二种:怕长度长的和直接回车的,都会设置失效位,读取会停止
- 第三种:可以可以知道读取停止是因为已经读取了整行还是由于数组已填满呢
-
mixtypes.cpp
- 结构体指针
- 结构体数组trio.trio是数组名,trio->year;数组名本质是地址,可以这样->,而不是.
- auto的作用:以后再看
-
newstrcut.cpp
-
numstr.cpp
- 用户根本没有输入地址的机会。问题在于,当cin读取年份,将回车键生成的换行符留在了输入队列中。
-
ptrstr.cpp
-
cout<<字符串地址,输出字符串;可以接受char animal[20]的animal,const char * bird的bird -
delete [] ps; -
ps = animal;指向同地址 -
ps = new char[strlen(animal) + 1]; strcpy(ps,aniaml); -
可以cout<< (int *) animal来看animal字符串的地址 -
如果直接char * ps;接着cin >> ps; 不行,因为ps的指针是未知的 -
内存必须先申请再读写 -
strtype1/2/3/4.cpp
- #include // C-style string library
- C风格:strcpy,strcat,strlen
- 未被初始化的数据,第一个空字符的出现位置是随机的,对于char charr[20];
- cin.getline(charr, 20); charr的输入
- getline(cin, str); str的输入
-
use_new.cpp
- double * pd = new double; *pd = 10000001.0;
- 地址在堆区,指针在栈区
-
第五章代码
-
第六章代码
-
cctypes.cpp
-
condit.cpp
-
enum.cpp
- enum {red, orange, yellow, green, blue, violet, indigo};
- 对应0-6
-
outfile.cpp
-
ofstream outFile; -
outFile.open(“carinfo.txt”); -
outFile << fixed;
outFile.precision(2);
outFile.setf(ios_base::showpoint);
outFile << "Make and model: " << automobile << endl;
outFile << "Year: " << year << endl;
outFile << "Was asking $" << a_price << endl;
outFile << "Now asking $" << d_price << endl;
outFile.close(); // done with file
-
这里的outFile有点类似于cout -
sumafile.cpp
-
ifstream inFile;
if (!inFile.is_open()) // failed to open file
{
cout << "Could not open the file " << filename << endl;
cout << "Program terminating.\n";
// cin.get(); // keep window open
exit(EXIT_FAILURE);
}
while (inFile.good()) // while input good and not at EOF
{
++count; // one more item read
sum += value; // calculate running total
inFile >> value; // get next value
}
if (inFile.eof())
cout << "End of file reached.\n";
else if (inFile.fail())
cout << "Input terminated by data mismatch.\n";
else
cout << "Input terminated for unknown reason.\n";
if (count == 0)
cout << "No data processed.\n";
else
{
cout << "Items read: " << count << endl;
cout << "Sum: " << sum << endl;
cout << "Average: " << sum / count << endl;
}
inFile.close();
-
输入格式不对,如将字符输入给double型,看inFile.fail() -
到文件尾:inFile.eof() -
第七章
-
arfupt.cpp
- 函数声明
- 参数列表const double ar [ ]与const double * ar的含义完全相同
- const函数,const double * f1(const double ar[], int n);返回一个常量指针
- 函数指针
- 函数指针,将函数名改为(*p1)即可,也可以用auto p2 = f2
- 函数指针调用时,可以加上(*p1)(av,3),也可以不用直接,p1(av,3)
- 函数数组
- pa是函数数组,不能直接auto pe = {f1,f2,f3};,要先定义pa这个函数数组,才能用auto pb = pa; pa的定义:函数指针数组,同理,改为(*pa[3])即可
- *函数数组指针的使用pa [i] (av,3) 或者 (pb[i]) (av,3)
数组名 和&数组名 的区别
数组名 和&数组名 虽然在数值上相同,但是在类型上不同——数组名 是指向首个元素的指针,&数组名 是指向整个数组的指针。在指针加减整数的时候,前者以一个元素为颗粒度,后者以整个数组为颗粒度。- sizeof(array)是整个数组的
array 的值就等于&array[0] 的值- auto pc = &pa;用的时候加上*pc
- store return value
- const double * pdb = (*pd)[1] (av,3);
-
arrfun2.cpp
- sum = sum_arr(cookies + 4, 4);
- 函数参数是数组的时候,可以数组名的偏移,思维打开
-
arrfun3.cpp
-
for (i = 0; i < limit; i++)
{
cout << "Enter value #" << (i + 1) << ": ";
cin >> temp;
if (!cin) // bad input
{
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Bad input; input process terminated.\n";
break;
}
else if (temp < 0) // signal to terminate
break;
ar[i] = temp;
}
-
输入后,通过!cin判断是否是好的输入,若是不好,则cin.clear(),接着循环进行,直到get到回车,break; -
void show_array(const double ar[], int n); -
show的时候,要对这个数组加个const -
arrfun4.cpp
-
arrobj.cpp
- void fill(std::array<double, Seasons> * pa);修改要加指针,(*pa)[i];
- fill(&expenses);
- void show(std::array<double, Seasons> da);
- show(expenses);
- 函数fill()和show()都有缺点。函数show()存在的问题是,expenses存
储了四个double值,而创建一个新对象并将expenses的值复制到其中的 效率太低。如果修改该程序,使其处理每月甚至每日的开支,这种问题 将更严重。show传参传入会复制一新对象,所以效率低下 -
funptr.cpp
- 函数指针作为参数
- void estimate(int lines, double (*pf)(int))
- (*pf)(lines)
- estimate(code, betsy);
- double betsy(int lns)
-
lotto.cpp
- unsigned本身是unsigned int的缩写
- cin >> total >> choicesk可以作逻辑词
-
ruler.cpp
-
strctptr.cpp
-
void rect_to_polar(const rect * pxy, polar * pda); -
void show_polar (const polar * pda); -
while (cin >> rplace.x >> rplace.y)
{
rect_to_polar(&rplace, &pplace); // pass addresses
show_polar(&pplace); // pass address
cout << "Next two numbers (q to quit): ";
}
//挺优雅的
-
strgback.cpp
-
strgfun.cpp
-
const char * str, str是指针,可以++来遍历,*str是 -
unsigned int c_in_str(const char * str, char ch)
{
unsigned int count = 0;
while (*str) // quit when *str is '\0'
{
if (*str == ch)
count++;
str++; // move pointer to next char
}
return count;
}
-
structfun.cpp
-
第八章代码
-
arrtemp.cpp
-
template <class T, size_t n>
void display(const std::array<T, n> & ar);
-
模板类声明 -
这里用模板类 -
std::size_t是一个typedef,对应于合适的整型,在我的电脑上是long unsigned int -
choices.cpp
-
template<class T>
T lesser(T a, T b)
-
函数调用与模板函数和非模板函数都匹配,因此选择非模板函数,返回20。 -
lesser<>(m, n)有“<>”这个符号,一定是用模板 -
lesser(x, y),虽然输入x,y是double,但强行用int模板 -
filefunct.cpp
-
方法setf( )返回调用它之前有效的所有格式化设置。 -
同理,os.precision(0)也是 -
void file_it(ostream & os, double fo, const double fe[],int n)
ios_base::fmtflags initial;
initial = os.setf(ios_base::fixed, ios_base::floatfield);
std::streamsize sz = os.precision(0);
-
ofstream是ostream的子类 -
funtemp.cpp
-
inline.cpp
- inline double square(double x) { return x * x; }
- 整个函数定义都放在一行中,但并不一定非得这样做。然而,如果函数定义占用多行(假定没有使用冗长的标识符),则将其作为内联函数就不太合适。
- 内联函数比宏好
- 宏不能按值传递,如当输入参数为4.5+7或者输入参数为c++,就不行
-
left.cpp
- char * left(const char * str, int n)
- 返回数组时,可以在函数里面new: char * p = new char[n+1];
- 但需要在外面delete
- char * left(const char * str, int n = 1);在函数原型的时候,=1,可以默认参数,这样不输入n参数时,默认n=1
-
leftover.cpp
-
strquote.cpp
-
用const 修饰函数的返回值,如果给以“指针传递”方式的函数返回值加const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。 -
例如函数:
const char * GetString(void);
如下语句将出现编译错误:
char *str = GetString();
正确的用法是
const char *str = GetString();
如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加const 修饰没有任何价值。
例如不要把函数int GetInt(void) 写成const int GetInt(void)。
函数返回值采用“引用传递”的场合并不多,这种方式一般只出现在类的赋值函数中,目的是为了实现链式表达。
class A
{
A & operate = (const A &other); // 赋值函数
};
A a, b, c; // a, b, c 为A 的对象
a = b = c; // 正常的链式赋值
(a = b) = c; // 不正常的链式赋值,但合法
如果将赋值函数的返回值加const 修饰,那么该返回值的内容不允许被改动。上例中,语句 a = b = c 仍然正确,但是语句 (a = b) = c 则是非法的。
-
const 成员函数(const的作用:说明其不会修改数据成员) -
如果在编写const 成员函数时,不慎修改了数据成员,或者调用了其它非const 成员函数,编译器将指出错误
a. const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.
b. const对象的成员是不可修改的,然而const对象通过指针维护的对象却是可以修改的.
c. const成员函数不可以修改对象的数据,不管对象是否具有const性质.它在编译时,以是否修改成员数据为依据,进行检查.
e. 然而加上mutable修饰符的数据成员,对于任何情况下通过任何手段都可修改,自然此时的const成员函数是可以修改它的。
-
const引用可以读取但是不可以被修改引用对象,任何对const引用进行赋值都是不合法的,它适用指向const对象的引用,而非const的引用不适用于指向const对象的引用。 -
swaps.cpp
-
twoswap.cpp
-
可以提供一个具体化函数定义——称为显式具体化(explicit specialization),其中包含所需的代码。当编译器找到与函数调用匹配的具体化定义时,将使用该定义,而不再寻找模板。 -
template <typename T>
void Swap(T &a, T &b);
template <> void Swap<job>(job &j1, job &j2);
//当参数为Job对象时,将使用显示具体化
-
tempover.cpp
- 当重载函数
- void ShowArray(T arr[], int n);
- void ShowArray(T * arr[], int n);
- 重载解析将寻找最匹配的函数。如果只存在一个这样的函数,则选择它;如果将模板B从程序中删除,则编译器将使用模板A来显示pd的内容,因此显示的将是地址,而不是值。
-
第九章代码
-
external.cpp support.cpp
-
::warming作用域解析运算符(::),放在变量名前面时,该运算符表示使用变量的全局版本。 -
extern double warming; // use warming from another file使用别的文件的全局变量,要用extern来声明它 -
CMakeLists.txt配置 -
add_library(support_library STATIC support.cpp )
add_executable(my_cmake_exe external.cpp)
target_link_libraries( my_cmake_exe support_library )
-
file1.cpp coordin.h file2.cpp
- .h文件定义了结构体和函数原型
- file2.cpp实现了头文件的函数
- file1.cpp调用了该头文件中的函数
- 这里如果头文件在已知目录下,add_library(support_library STATIC file2.cpp )会自动去已知目录下找coordin.h因为file2.cpp里面有#include “coordin.h”
-
namesp.h namesp.cpp usenmsp.cpp
-
“namesp.h“中:
namespace pers
{
定义结构体;
函数原型;
}
namespace debts
{
using namespace pers;//使用刚定义的名称空间
}
-
“namesp.cpp“中:
namespace pers
{
写函数
}
-
“usenmsp.cpp“中:
using debts::Debt;
using debts::showDebt;
using namespace debts;
-
twofile1.cpp twofile2.cpp
-
twofile1.cpp使用twofile2.cpp的内容 -
twofile1.cpp中的int tom=3 twofile2.cpp使用extern int tom; -
twofile1.cpp中的int dick = 30; twofile2.cpp使用static int dick = 10; -
twofile1.cpp中的static int harry = 300; twofile2.cpp使用int harry = 200; -
默认是extern -
不能两个文件都int errors=3 这种做法将失败,因为它违反了单定义规则。file2中的定义试图创建一个外部变量,因此程序将包含errors的两个定义,这是错误。但如果文件定义了一个静态外部变量,其名称与另一个文件中声明的常规外部变量相同,则在该文件中,静态变量将隐藏常规外部变量. -
newplace.cpp
-
定位new运算符 -
new运算符还有另一种变体,被称为定位(placement)new运算符,它让您能够指定要使用的位置。 -
char buffer[BUF]; // chunk of memory静态区 -
(void *) buffer来看内存地址 -
pd2 = new (buffer) double[N];
pd2 = new (buffer + N * sizeof(double)) double[N];
-
不需要delete,因为new的不在动态存储区 -
static.cpp
-
静态变量total只在程序运行时被设置为0,以后在两次函数调用之间,其值将保持不变,因此能够记录读取的字符总数。 -
using namespace std;
char input[ArSize];
char next;
cout << "Enter a line:\n";
cin.get(input, ArSize);
while (cin)
{
cin.get(next);
while (next != '\n') // string didn't fit!
cin.get(next); // dispose of remainder
strcount(input);
cout << "Enter next line (empty line to quit):\n";
cin.get(input, ArSize);
}
cout << "Bye\n";
-
tip: C++也为静态存储持续性变量提供了3种链接性:外部链接性(可在其他文件中访问)、内部链接性(只能在当前文件中访问)和无链接性(只能在当前函数或代码块中访问) -
补充:cv限定符,cv表示const和volatile
- 在C++看来,全局const定义(如下述代码段所示)就像使用了static说明符一样。
- const int finger = 10; same as ------ static const int finger = 10;
-
第十章代码
-
stock.h stock.cpp
-
通过内联函数来使得不需要重复输入计算代码 -
Stock(); // default constructor
Stock(const std::string & co, long n = 0, double pr = 0.0);
~Stock(); // noisy destructor
-
默认构造函数 company = "no name";
shares = 0;
share_val = 0.0;
total_val = 0.0;
-
this是个对象指针,返回对象,要加* -
使用对象指针的函数:&top->topval(stocks[st]) -
作用域为类的常量
-
一种方式是在类中声明一个枚举 用这种方式声明枚举并不会创建类数据成员。也就是说,所有对象中都不包含枚举。另外,Months只是一个符号名称,在作用域为整个类的代码中遇到它时,编译器将用30来替换它 -
另一种在类中定义常量的方式——使用关键字static static const int Months = 12; -
第十一章代码
-
运算符重载函数
-
Time operator+(const Time & t) const; -
morefixing.operator+(total); -
total = weeding + waxing; -
Time operator*(double n) const;
friend Time operator*(double m, const Time & t)
{ return t * m; } // inline definition
//这样数*对象和对象*数都实现了
-
友元函数
-
通过让函数成为类的友元,可以赋予该函数与类的成员函数相同的访问权限。 -
对于非成员重载运算符函数来说,运算符表达式左边的操作数对应于运算符函数的第一个参数,运算符表达式右边的操作数对应于运算符函数的第二个参数。 -
虽然该友元函数在类声明中声明,但是它不是成员函数,因此不能使用成员运算符来调用; -
虽然该友元函数不是成员函数,但它与成员函数的访问权限相同 -
编写函数定义。因为它不是成员函数,所以不要使用Time::限定符。另外,不要在定义中使用关键字friend -
加了const好像不能当左值:os << t.hours;所以std::ostream & os不能加const -
std::ostream & operator<<(std::ostream & os, const Time & t)
{
os << t.hours << " hours, " << t.minutes << " minutes";
return os;
}//return os 因为才能在同一行多次<<
-
如果函数功能在其他函数实现了,可以调用其他函数: -
friend Time operator*(double m, const Time & t)
{ return t * m; }
-
转换函数1
- 当构造函数只接受一个参数时,可以使用:Stonewt incognito = 257;
- Stonewt incognito(257);
- Stonewt incognito = Stonewt(257);
- 后两种也可以接受多参数输入
- 定义后,可以incognito = 276.8; taft = 325; same as taft = Stonewt(325);
- void display(const Stonewt & st, int n); display(422, 2);
-
转换函数2
- operator int() const; operator double() const;
- Stonewt poppins(9,2.8); 使用double p_wt = poppins; 时候会使用到
- int (poppins)也会使用到
- Vector Vector::operator-() const;当输入参数为0个时,为负号重载运算符
-
第十二章代码
-
stringbad.h stringbad.cpp vegnews.cpp
- 它使用char指针(而不是
char数组)来表示姓名。这意味着类声明没有为字符串本身分配存储空间,而是在构造函数中使用new来为字符串分配空间。这避免了在类声明中预先定义字符串的长度。 - 其次,将num_strings成员声明为静态存储类。只是为了方便说明静态数据成员,并指出潜在的编程问题,字符串类通常并不需要这样的成员。
- str = new char[len + 1];
- delete [] str;
- 传入const char * s,计算长度len = std::strlen(s);
- std::strcpy(str, s);
- 不能在类声明中初始化静态成员变量,这是因为声明描述了如何分配内存,但并不分配内存。您可以使用这种格式来创建对象,从而分配和初始化内存。对于静态类成员,可以在类声明之外,如在stringbad.cpp而不是在头文件,使用单独的语句来进行初始
- 字符串并不保存在对象中。字符串单独保存在堆内存中,对象仅保存了指出到哪里去查找字符串的信息。
- 要创建字符串副本,所以不能直接str=s,防止重复释放
- 首先,将headline2作为函数参数来传递从而导致析构函数被调用。其次,虽然按值传递可以防止原始参数被修改,但实际上函数已使原始字符串无法识别,导致显示一些非标准字符(显示的文本取决于内存中包含的内容)。
- 主函数:创建了三个对象,一个用引用传递参数,一个用按值传递,一个复制构造函数,一个赋值运算符
- 默认复制构造是浅拷贝,按值传递参赛后,会调用,然后函数结束会自动析构,造成问题
- 因为自动存储对象被删除的顺序与创建顺序相反,所以最先删除的3个对象是knots、sailor和sport。
- StringBad knot;会调用默认构造函数,也是会创建对象的
- 在类声明初始化的静态:static const,enum
-
sting1.h string1.cpp sayings1.cpp saying2.cpp
-
String::String(const char * s) // 构造函数
{
len = std::strlen(s); // set size
str = new char[len + 1]; // allot storage
std::strcpy(str, s); // initialize pointer
num_strings++; // set object count
}
-
String & String::operator=(const String & st) //赋值运算符
{
if (this == &st)
return *this;
delete [] str;//先删除本身
len = st.len;
str = new char[len + 1];
std::strcpy(str, st.str);
return *this;
}
-
new char[1]与new char分配内存量一致,但需要兼容delete []所以使用前者 -
delete[]与空指针兼容。因此也可用str = nullptr来指向空指针 -
返回对象将调用复制构造函数,而返回引用不会。 -
定位new运算符
-
将delete用于pc2和pc4时,将自动调用为pc2和pc4指向的对象调用析构函数;然而,将delete[]用于buffer时,不会为使用定位new运算符创建的对象调用析构函数。 -
pc3->~JustTesting(); // destroy object pointed to by pc3
pc1->~JustTesting(); // destroy object pointed to by pc1
delete [] buffer; // free buffer
对于使用定位new运算符创建的对象,应以与创建顺序相反的顺序进行删除。 原因在于,晚创建的对象可能依赖于早创建的对象。另外,仅当所有对象都被销毁后,才能释放用于存储这些对象的缓冲区。 -
C++11提供了另一种禁用方法的方式——使用关键字delete,与其将来面对无法预料的运行故障,不如得到一个易于跟踪的编译错误,指出这些方法是不可访问的。 -
C++为类构造函数提供了一种可用来初始化数据成员的特殊语法。这种语法包括冒号和由逗号分隔的初始化列表,被放在构造函数参数的右括号后,函数体的左括号之前。每一个初始化器都由被初始化的成员的名称和包含初始值的括号组成。从概念上来说,这些初始化操作是在对象创建时进行的,此时函数体中的语句还没有执行。语法如下:
- Queue::Queue(int qs) : qsize(qs),front(NULL){}
-
第十三章代码
-
第十四章代码
-
第十五章代码
|