一、#include “filename.h”和#include <filename.h>的区别 KlMrM% ;y
O5HK2Xg,C
#include “filename.h”是指编译器将从当前工作目录上开始查找此文件 `}:q@:%
5~T`R~Uqb
#include <filename.h>是指编译器将从标准库目录中开始查找此文件 Fy|tKMhnc
c$),/0td|
J+f
.r|?
二、头文件的作用 n}9vAvC
6AeX$>k+
加强安全检测 -lHSojq~H
RXa&*Jtr -
通过头文件可能方便地调用库功能,而不必关心其实现方式 L(a&,cdh
P( >*gp
hzIP ?0^E
三、* , &修饰符的位置 {@Y|"qIN
h8;B +#f`
对于*和&修饰符,为了避免误解,最好将修饰符紧靠变量名 6~8A$:
8<(qN>R
f}q4~NPn-
四、if语句 y+f@8]
[Nb0&:$ay
不要将布尔变量与任何值进行比较,那会很容易出错的。 !g}?x3
j.Ro(0%
整形变量必须要有类型相同的值进行比较 UpL1C~&
sg"J00
浮点变量最好少比点,就算要比也要有值进行限制 Az4+([
7'wt/9
指针变量要和NULL进行比较,不要和布尔型和整形比较 hn9'M!*:O
fl| 8#\r
3`PPTG
五、const和#define的比较 j-wSsjLk
*yJCnoF
const有数据类型,#define没有数据类型 oTOr,Mn0\6
R;,&s!\<
个别编译器中const可以进行调试,#define不可以进行调试 N6wea]
WP, Ll\K)7
在类中定义常量有两种方式 {awv=s
.`Ey'T_
1、 在类在声明常量,但不赋值,在构造函数初始化表中进行赋值; ?sQOz[ig;
;,T3C:S?
2、 用枚举代替const常量。 %H=d_Nm{
*,$cW,LN
/BB(riG
六、C++函数中值的传递方式 _t<D~
|J:n'}
有三种方式:值传递(Pass by value)、指针传递(Pass by pointer)、引用传递(Pass by reference) XWH{+c"
zjVBMqdD
void fun(char c) //pass by value *0>![v
AR9D;YfR~
void fun(char *str) //pass by pointer j)4:*R.Z]
+_Nr a
void fun(char &str) //pass by reference ,ra!O=d~0
Sa5+_TW
如果输入参数是以值传递的话,最好使用引用传递代替,因为引用传递省去了临时对象的构造和析构 -dXlGOD+C
? b;_T,S[
函数的类型不能省略,就算没有也要加个void H/8H`9S$
<CrNDY
ACQc
0:q
七、函数体中的指针或引用常量不能被返回 C[f'1O7
.!uXhF'
Char *func(void) P:GAJ->;]>
e~#;ux
{ "YU<CO;4VV
yuyI)ebC
char str[]=”Hello Word”; l*^J}oY
W[trsFP1?
//这个是不能被返回的,因为str是个指定变量,不是一般的值,函数结束后会被注销掉 @tQu3Rq@
H;('h#=cD
return str; kev|AU (WX
*1FDK{
} ^%(HZ'$wC
W;~ f865
函数体内的指针变量并不会随着函数的消亡而自动释放 (S1c6~
%@/"BF;r
(Fc\*Vn
八、一个内存拷贝函数的实现体 +O`3eP`u
f4A;v|5_
void *memcpy(void *pvTo,const void *pvFrom,size_t size) ,(d\! T/]'
&)UZ9r`z
{ oNW.-gNT
y
%R-Oc
assert((pvTo!=NULL)&&(pvFrom!=NULL)); O@*7O~eO
V_b"^911r
byte *pbTo=(byte*)pvTo; //防止地址被改变 "B18|#v
Leg)q7n
byte *pbFrom=(byte*)pvFrom; RmF,x9
\G}02h
while (size-- >0) { +d](+$
+NIq}fZn9
pbTo++ = pbForm++; ra87~kj<
Ze `=n
return pvTo; ZAe'lgS
iuxI$
} XO[S(q
m]C|8b7Y
c6v@6jzx0Y
九、内存的分配方式 m\9R;$\
B4tC3r
分配方式有三种,请记住,说不定那天去面试的时候就会有人问你这问题 =;9
%Q{
i.QS(gM
1、 静态存储区,是在程序编译时就已经分配好的,在整个运行期间都存在,如全局变量、常量。 Ew`(x30E
p~(+4uA
2、 栈上分配,函数内的局部变量就是从这分配的,但分配的内存容易有限。 Ck`-<)uN
T@K=
*p
3、 堆上分配,也称动态分配,如我们用new,malloc分配内存,用delete,free来释放的内存。 :P,g,
?vA)F)MS
.h({ P#QT
十、内存分配的注意事项 Uc>kiWW
Ej_ >*^b
用new或malloc分配内存时,必须要对此指针赋初值。 G6W_)YL
Y-Iu&H+\
用delete 或free释放内存后,必须要将指针指向NULL !H)$_d \uj
|nOqy&B
不能修改指向常量的指针数据 ;Dh\2! sr
z@bq*':~J
++9?LH4S4
十一、内容复制与比较 ;_$Q~X
m1pge4*
//数组…… )FLDCer
PjwDth
A1
char a[]=”Hello Word!”; r4YiXss
[z:.52@!
char b[10]; HgGwV;W
*lZ;kW(}p
strcpy(b,a); ^pB}eh.@U
fL xGaOT
if (strcmp(a,b)==0) W4OL{p-\/
e0s*
{} !
qVuhad.
C8{bqmlm@
//指针…… + 6noQYe
Q!9
char a[]=”Hello Word!”; n8pvzlj1
8
x=J&d
char *p; }Z="}Dg|T
vl`Qz"Xy
p=new char[strlen(a)+1]; 9f(0
qa
DB~3(r?K
strcpy(p,a); +N6IdDN3
bk(q8xR`
if (strcmp(p,a)==0) L/J1;
/"+CH\)
E
{} 8ln{!,j;
UC
e{V ]T
QJ
i5 H
十二、sizeof的问题 (6}[y\a+
h 8%(,$*
记住一点,C++无法知道指针所指对象的大小,指针的大小永远为4字节 <wH"{G3?
x5w5xw
char a[]=”Hello World!” |mM K9OEu
;\]&k
char *p=a; *&vlfH
tG7F!um(
count<<sizeof(a)<<end; //12字节 6N49q-.Lg
TdU'L:<4l
count<<sizeof(p)<<endl; //4字节 c>|1%}"?
opXxtYC@
而且,在函数中,数组参数退化为指针,所以下面的内容永远输出为4 d/8p?Km
)_&P:;N
void fun(char a[1000]) ndmsXls
bIWSNNV0F
{ JpRn)e'Z
!"g2F}n
count<<sizeof(a)<<endl; //输出4而不是1000 QGCg~TV;
Aaw]=8 OI
} c$.Zg=
H|Y*TI2vf8
.Ei#mG-=}&
十三、关于指针 sck.2-f"
ptc.JB6
1、 指针创建时必须被初始化 |C"zK
|EGC1x]j=
2、 指针在free 或delete后必须置为NULL rNK<p3=7)
}PXtwp13&u
3、 指针的长度都为4字节 bA-/"'Vp9
KqL+R$??"(
4、释放内存时,如果是数组指针,必须要释放掉所有的内存,如 S.zY0
@tX8M[.eA
char *p=new char[100]; DL*&e|:q
qyKI.X3n*
strcpy(p,”Hello World”); *|9:
o5E5s9n
delete []p; //注意前面的[]号 | |u
#ZC9=
p=NULL; !X5LgMw^ ;
~eZ]LW])
5、数组指针的内容不能超过数组指针的最大容易。 HdR TdV
zNO,vR[\
如: wX4gyr
+h)1NX;o1
char *p=new char[5]; U]]ON6Y&F
ae#Qeow`
strcpy(p,”Hello World”); //报错 目标容易不够大 X:/7#fcG8
?$ Dc>
delete []p; //注意前面的[]号 jK]An;l{Z
p[K!.vOt+
p=NULL; tZ.hSDH
=E$B0^_2RC
-l~+cI \2
十四、关于malloc/free 和new /delete UL.YDU)
^H!45ph?Jc
l malloc/free 是C/C+的内存分配符,new /delete是C++的内存分配符。 Eb7GiRT#
,_UTeW6M
l 注意:malloc/free是库函数,new/delete是运算符 uC! dy
`J$7X
l malloc/free不能执行构造函数与析构函数,而new/delete可以 l*z+<c6$_
KJ 7-Vl>
l new/delete不能在C上运行,所以malloc/free不能被淘汰 `)tIXMn
\ 62!{
l 两者都必须要成对使用 d3]<'B:nb
P9o=G=i
l C++中可以使用_set_new_hander函数来定义内存分配异常的处理 d}2(G2z^
O|nLIfT
,YBe|3
十五、C++的特性 4iv&!hAc;
Yy{(XBJ~%t
C++新增加有重载(overload),内联(inline),Const,Virtual四种机制 eGLB,29g
P&h]uNu
重载和内联:即可用于全局函数,也可用于类的成员函数; $q##Tys
uE}$ZBiq
Const和Virtual:只可用于类的成员函数; X>i{288M3
cAn_:^
重载:在同一类中,函数名相同的函数。由不同的参数决定调用那个函数。函数可要不可要Virtual关键字。和全局函数同名的函数不叫重载。如果在类中调用同名的全局函数,必须用全局引用符号::引用。 A[`2Mnj
!-m 'diE
覆盖是指派生类函数覆盖基类函数 &
h\!#X0
*mz-g7
函数名相同; !E6QED"
H@te!EE
参数相同; i!*8@:VI
b"nD5r
基类函数必须有Virtual关键字; }LY)FT4n
} J`cRDO
不同的范围(派生类和基类)。 8<{i=V*x4
lf\^!E:
隐藏是指派生类屏蔽了基类的同名函数相同 YH&q5W,KX
aP]h03sS
1、 函数名相同,但参数不同,此时不论基类有无Virtual关键字,基类函数将被隐藏。 IN,=v+A
/@1pm/>ZaN
2、 函数名相同,参数也相同,但基类无Virtual关键字(有就是覆盖),基类函数将被隐藏。 G1Vn[[%k
k3T374t1b
内联:inline关键字必须与定义体放在一起,而不是单单放在声明中。 ZA \;9M=
xKkXr-yb`f
Const:const是constant的缩写,“恒定不变”的意思。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。 "TVmxE%(
~
\b~
1、 参数做输入用的指针型参数,加上const可防止被意外改动。 # S(b2LEc
7u:QT2=&
2、 按值引用的用户类型做输入参数时,最好将按值传递的改为引用传递,并加上const关键字,目的是为了提高效率。数据类型为内部类型的就没必要做这件事情;如: + (Jh$b_
VNs3.
将void Func(A a) 改为void Func(const A &a)。 AzVv-!Y
uQ%3?bx)T
而void func(int a)就没必要改成void func(const int &a); X6j:TF
/i{V21(%
3、 给返回值为指针类型的函数加上const,会使函数返回值不能被修改,赋给的变量也只能是const型变量。如:函数const char*GetString(void); char *str=GetString()将会出错。而const char *str=GetString()将是正确的。 aK8s0G!z?5
U_RWqKL
4、 Const成员函数是指此函数体内只能调用Const成员变量,提高程序的键壮性。如声明函数 int GetCount(void) const;此函数体内就只能调用Const成员变量。 $$XeCPs0
6(>,qt,9S
Virtual:虚函数:派生类可以覆盖掉的函数,纯虚函数:只是个空函数,没有函数实现体; /I:&P Pff
i]Bu7Fuu
qCB{dp/
十六、extern“C”有什么作用? lx7]rkWo|a
F##xVmR~
Extern “C”是由C++提供的一个连接交换指定符号,用于告诉C++这段代码是C函数。这是因为C++编译后库中函数名会变得很长,与C生成的不一致,造成C++不能直接调用C函数,加上extren “c”后,C++就能直接调用C函数了。 @aP1[( m
TiR00#b
Extern “C”主要使用正规DLL函数的引用和导出 和 在C++包含C函数或C头文件时使用。使用时在前面加上extern “c” 关键字即可。 6`X}Z'4.Ox
,20l` :
{&a6<y#-
十七、构造函数与析构函数 7.]H9
>uDC!0)R
派生类的构造函数应在初始化表里调用基类的构造函数; i1K$~
f`iDF+h<6
派生类和基类的析构函数应加Virtual关键字。 !JBj%| !
u'^kpr`y
不要小看构造函数和析构函数,其实编起来还是不容易。 d5`D[,]d
X|aD>CT
#include <iostream.h> S|fb'
biS{.
class Base HBZ6 Pj
dkeMiLm
{ Ko)f:=Qo
IG:2<G
public: nb ?(zDJ8
cI&XsnY
virtual ~Base() { cout<< "~Base" << endl ; } Gzs$0Ki=
Y[W :Zhl;
}; 50`|#zF^#
RRQIlI<
class Derived : public Base nTD4^'
W0}FOfL9
{ Rd<K.7&A}
>s )L(DHa"
public: 5hh6;)
LnM$@
virtual ~Derived() { cout<< "~Derived" << endl ; } lBa` nG
xZY7X&C4
}; $R+rB;=a!
QMy1!:Z&!
void main(void) #$]8WSl
0M?zotv0#
{ @(0O9L
F
KT17I&:
Base * pB = new Derived; // upcast a!f71k
r
%xKZ"#Z#K
delete pB; .gM6m8l9wp
7u
rD
} c&Eva
D;*cy<_K8
输出结果为: c`/=)IO4%
rHuzGSX54
~Derived
d ^zuo
wEN[o18{
~Base #N%j9
G:@1.H`
如果析构函数不为虚,那么输出结果为 dk"@2%xJ2d
c]i;0j? Dl
~Base 2dK:VC4U
,6o tm
"rfBYl`
十八、#IFNDEF/#DEFINE/#ENDIF有什么作用 uvw1 _j?
oX'@,(6)
仿止该头文件被重复引用