传智播客基础课程讲义vWord格式.docx
《传智播客基础课程讲义vWord格式.docx》由会员分享,可在线阅读,更多相关《传智播客基础课程讲义vWord格式.docx(47页珍藏版)》请在冰点文库上搜索。
usingnamespacestd;
这样命名空间std内定义的所有标识符都有效(曝光)。
就好像它们被声明为全局变量一样。
那么以上语句可以如下写:
cout<
因为标准库非常的庞大,所以程序员在选择的类的名称或函数名时就很有可能和标准库中的某个名字相同。
所以为了避免这种情况所造成的名字冲突,就把标准库中的一切都被放在名字空间std中。
但这又会带来了一个新问题。
无数原有的C++代码都依赖于使用了多年的伪标准库中的功能,他们都是在全局空间下的。
所以就有了<
和<
等等这样的头文件,一个是为了兼容以前的C++代码,一个是为了支持新的标准。
命名空间std封装的是标准程序库的名称,标准程序库为了和以前的头文件区别,一般不加"
.h"
2C++命名空间定义及使用语法
/*
在C++中,名称(name)可以是符号常量、变量、宏、函数、结构、枚举、类和对象等等。
为了避免,在大规模程序的设计中,以及在程序员使用各种各样的C++库时,这些标识符的命名发生冲突,
标准C++引入了关键字namespace(命名空间/名字空间/名称空间/名域),可以更好地控制标识符的作用域。
*/
std是c++标准命名空间,c++标准程序库中的所有标识符都被定义在std中,比如标准库中的类iostream、vector
等都定义在该命名空间中,使用时要加上using声明(usingnamespacestd)或using指示(如std:
string、
std:
vector<
int>
).
C中的命名空间
在C语言中只有一个全局作用域
C语言中所有的全局标识符共享同一个作用域
标识符之间可能发生冲突
C++中提出了命名空间的概念
命名空间将全局作用域分成不同的部分
不同命名空间中的标识符可以同名而不会发生冲突
命名空间可以相互嵌套
全局作用域也叫默认命名空间
C++命名空间的定义:
namespacename{…}
C++命名空间的使用:
使用整个命名空间:
usingnamespacename;
使用命名空间中的变量:
usingname:
variable;
使用默认命名空间中的变量:
variable
默认情况下可以直接使用默认命名空间中的所有标识符
3C++命名空间编程实践
namespaceNameSpaceA
{
inta=0;
}
namespaceNameSpaceB
inta=1;
namespaceNameSpaceC
{
structTeacher
{
charname[10];
intage;
};
}
intmain()
usingnamespaceNameSpaceA;
usingNameSpaceB:
NameSpaceC:
Teacher;
printf("
a=%d\n"
a);
NameSpaceB:
a);
NameSpaceB:
Teachert2
Teachert1={"
aaa"
3};
=%s\n"
;
=%d\n"
system("
pause"
);
return0;
4结论
1)当使用<
的时候,该没有定义全局命名空间,必须使用namespacestd;
若不引入usingnamespacestd,需要这样做。
cout。
2)c++标准为了和C区别开,也为了正确使用命名空间,规定不使用后缀.h。
3)C++命名空间的定义:
4)usingnamespaceNameSpaceA;
5)namespce定义可嵌套。
“实用性”增加
#include"
iostream"
usingnamespacestd;
ocx》
变量检测增强
在C语言中,重复定义多个同名的全局变量是合法的
在C++中,不允许定义多个同名的全局变量
C语言中多个同名的全局变量最终会被链接到全局数据区的同一个地址空间上
intg_var;
intg_var=1;
C++直接拒绝这种二义性的做法。
intmain(intargc,char*argv[])
g_var=%d\n"
g_var);
struct类型加强
struct类型的加强:
C语言的struct定义了一组变量的集合,C编译器并不认为这是一种新的类型
C++中的struct是一个新类型的定义声明
structStudent
charname[100];
intage;
};
Students1={"
wang"
1};
Students2={"
wang2"
2};
C++中所有的变量和函数都必须有类型
C++中所有的变量和函数都必须有类型
C语言中的默认类型在C++中是不合法的
函数f的返回值是什么类型,参数又是什么类型?
函数g可以接受多少个参数?
pp试试
f(i)
i=%d\n"
i);
g()
return5;
f(10);
g()=%d\n"
g(1,2,3,4,5));
getchar();
总结:
在C语言中
intf();
表示返回值为int,接受任意参数的函数
intf(void);
表示返回值为int的无参函数
在C++中
intf();
和intf(void)具有相同的意义,都表示返回值为int的无参函数
C++更加强调类型,任意的程序元素都必须显示指明类型
属于语法级别的增强。
新增Bool类型关键字
C++中的布尔类型
C++在C语言的基本类型系统之上增加了bool
C++中的bool可取的值只有true和false
理论上bool只占用一个字节,
如果多个bool变量定义在一起,可能会各占一个bit,这取决于编译器的实现
true代表真值,编译器内部用1来表示
false代表非真值,编译器内部用0来表示
bool类型只有true(非0)和false(0)两个值
C++编译器会在赋值时将非0值转换为true,0值转换为false
inta;
boolb=true;
b=%d,sizeof(b)=%d\n"
b,sizeof(b));
b=4;
a=b;
a=%d,b=%d\n"
a,b);
b=-4;
a=10;
b=a;
b=0;
b=%d\n"
b);
三目运算符功能增强
1三目运算符在C和C++编译器的表现
inta=10;
intb=20;
....\n"
解释:
C++编译器对const常量的处理
当碰见常量声明时,在符号表中放入常量=?
问题:
那有如何解释取地址
编译过程中若发现使用常量则直接以符号表中的值替换
编译过程中若发现对const使用了extern或者&
操作符,则给对应的常量分配存储空间(兼容C)
?
联想:
int&
a=1(err)&
constint&
a=10(ok)?
C++中const符号表原理图
注意:
C++编译器虽然可能为const常量分配空间,但不会使用其存储空间中的值。
结论:
C语言中的const变量
C语言中const变量是只读变量,有自己的存储空间
C++中的const常量
可能分配存储空间,也可能不分配存储空间
当const常量为全局,并且需要在其它文件中使用
当使用&
操作符取const常量的地址
3const和#define相同之处
."
return;
4引用的意义
1)引用作为其它变量的别名而存在,因此在一些场合可以代替指针
2)引用相对于指针来说具有更好的可读性和实用性
5引用本质思考
思考1:
C++编译器背后做了什么工作?
inta=10;
b=a;
3const引用结论
1)Const&
inte相当于constint*conste
2)普通引用相当于int*conste1
3)当使用常量(字面量)对const引用进行初始化时,C++编译器会为常量值分配空间,并将引用名作为这段空间的别名
4)使用字面量对const引用初始化后,将生成一个只读变量
4const修饰类
后续课程介绍
5综合练习
int&
j()
staticinta=0;
returna;
g()
inta=g();
int&
b=g();
j()=10;
f()=%d\n"
f());
7C++对C的函数扩展
1inline内联函数
C++中的const常量可以替代宏常数定义,如:
constintA=3;
?
#defineA3
C++中是否有解决方案替代宏代码片段呢?
(替代宏代码片段就可以避免宏的副作用!
)
C++中推荐使用内联函数替代宏代码片段
C++中使用inline关键字声明内联函数
内联函数声明时inline关键字必须和函数定义结合在一起,否则编译器会直接忽略内联请求。
函数重载的调用准则
编译器调用重载函数的准则
将所有同名函数作为候选者
尝试寻找可行的候选函数
精确匹配实参
通过默认参数能够匹配实参
通过默认类型转换匹配实参
匹配失败
最终寻找到的可行候选函数不唯一,则出现二义性,编译失败。
无法匹配所有候选者,函数未定义,编译失败。
函数重载的注意事项
重载函数在本质上是相互独立的不同函数(静态链编)
重载函数的函数类型是不同的
函数返回值不能作为函数重载的依据
函数重载是由函数名和参数列表决定的。
函数重载是发生在一个类中里面
函数重载遇上函数默认参数
函数重载和函数指针结合
函数重载与函数指针
当使用重载函数名对函数指针进行赋值时
根据重载规则挑选与函数指针参数列表一致的候选者
严格匹配候选者的函数类型与函数指针的函数类型
intfunc(intx)."
函数重载、重写、重定义
后续课程。
8附录
附录1:
C++语言对C语言扩充和增强的几点具体体现
附录2:
C语言register关键字—最快的关键字
register:
这个关键字请求编译器尽可能的将变量存在CPU内部寄存器中,而不是通过内存寻址访问,以提高效率。
注意是尽可能,不是绝对。
你想想,一个CPU的寄存器也就那么几个或几十个,你要是定义了很多很多register变量,它累死也可能不能全部把这些变量放入寄存器吧,轮也可能轮不到你。
一、皇帝身边的小太监----寄存器
?
不知道什么是寄存器?
那见过太监没有?
没有?
其实我也没有。
没见过不要紧,见过就麻烦大了。
^_^,大家都看过古装戏,那些皇帝们要阅读奏章的时候,大臣总是先将奏章交给皇帝旁边的小太监,小太监呢再交给皇帝同志处理。
这个小太监只是个中转站,并无别的功能。
好,那我们再联想到我们的CPU。
CPU不就是我们的皇帝同志么?
大臣就相当于我们的内存,数据从他这拿出来。
那小太监就是我们的寄存器了(这里先不考虑CPU的高速缓存区)。
数据从内存里拿出来先放到寄存器,然后CPU再从寄存器里读取数据来处理,处理完后同样把数据通过寄存器存放到内存里,CPU不直接和内存打交道。
这里要说明的一点是:
小太监是主动的从大臣手里接过奏章,然后主动的交给皇帝同志,但寄存器没这么自觉,它从不主动干什么事。
一个皇帝可能有好些小太监,那么一个CPU也可以有很多寄存器,不同型号的CPU拥有寄存器的数量不一样。
为啥要这么麻烦啊?
速度!
就是因为速度。
寄存器其实就是一块一块小的存储空间,只不过其存取速度要比内存快得多。
进水楼台先得月嘛,它离CPU很近,CPU一伸手就拿到数据了,比在那么大的一块内存里去寻找某个地址上的数据是不是快多了?
那有人问既然它速度那么快,那我们的内存硬盘都改成寄存器得了呗。
我要说的是:
你真有钱!
二、举例
register修饰符暗示编译程序相应的变量将被频繁地使用,如果可能的话,应将其保存在CPU的寄存器中,以加快其存储速度。
例如下面的内存块拷贝代码,
#ifdefNOSTRUCTASSIGN
memcpy(d,s,l)
{
registerchar*d;
?
registerchar*s;
registerinti;
while(i--)
*d++=*s++;
}
#endif
三、使用register修饰符的注意点
但是使用register修饰符有几点限制。
首先,register变量必须是能被CPU所接受的类型。
这通常意味着register变量必须是一个单个的值,并且长度应该小于或者等于整型的长度。
不过,有些机器的寄存器也能存放浮点数。
其次,因为register变量可能不存放在内存中,所以不能用“&
”来获取register变量的地址。
由于寄存器的数量有限,而且某些寄存器只能接受特定类型的数据(如指针和浮点数),因此真正起作用的register修饰符的数目和类型都依赖于运行程序的机器,而任何多余的register修饰符都将被编译程序所忽略。
在某些情况下,把变量保存在寄存器中反而会降低程序的运行速度。
因为被占用的寄存器不能再用于其它目的;
或者变量被使用的次数不够多,不足以装入和存储变量所带来的额外开销。
早期的C编译程序不会把变量保存在寄存器中,除非你命令它这样做,这时register修饰符是C语言的一种很有价值的补充。
然而,随着编译程序设计技术的进步,在决定那些变量应该被存到寄存器中时,现在的C编译环境能比程序员做出更好的决定。
实际上,许多编译程序都会忽略register修饰符,因为尽管它完全合法,但它仅仅是暗示而不是命令。
9作业及强化训练
1复杂数据类型引用做函数参数
分析内存四区变化图
2代码敲一遍
3设计一个类,求圆形的周长
4设计一个学生类,属性有姓名和学号,
可以给姓名和学号赋值
可以显示学生的姓名和学号
2、类和对象
1前言
C++学习技术路线及目标
研究C++编译器管理类和对象的方法===》避免死角
c++编译器对类对象的生命周期管理,对象创建、使用、销毁
c++面向对象模型初探
c++面向对象多态原理探究
操作符重载
C++基础课程学习完毕以后,有没有一个标准,来判断自己有没有入门。
面向抽象类(接口)编程
2类和对象
基本概念
1)类、对象、成员变量、成员函数
2)面向对象三大概念
封装、继承、多态
3)编程实践
类的定义和对象的定义,对象的使用
求圆形的面积
定义Teacher类,打印Teacher的信息(把类的声明和类的实现分开)
类的封装
1)封装(Encapsulation)
A)封装,是面向对象程序设计最基本的特性。
把数据(属性)和函数(操作)合成一个整体,这在计算机世界中是用类与对象实现的。
B)封装,把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
备注:
有2层含义(把属性和方法进行封装对属性和方法进行访问控制)
C++中类的封装
成员变量,C++中用于表示类属性的变量
成员函数,C++中用于表示类行为的函数
2)类成员的访问控制
在C++中可以给成员变量和成员函数定义访问级别
Public修饰成员变量和成员函数可以在类的内部和类的外部被访问
Private修饰成员变量和成员函数只能在类的内部被访问
pp
2C++编译器构造析构方案PK对象显示初始化方案
设计构造函数和析构函数的原因
面向对象的思想是从生活中来,手机、车出厂时,是一样的。
生活中存在的对象都是被初始化后才上市的;
初始状态是对象普遍存在的一个状态的
普通方案:
为每个类都提供一个public的initialize函数;
对象创建后立即调用initialize函数进行初始化。
优缺点分析
1)initialize只是一个普通的函数,必须显示的调用
2)一旦由于失误的原因,对象没有初始化,那么结果将是不确定的
没有初始化的对象,其内部成员变量的值是不定的
3)不能完全解决问题
n"
;
Location(constLocation&
p)<
endl;
~Location()
{
cout<
X<
"
"
<
Y<
Objectdestroyed."
intGetX(){returnX;
}intGetY(){returnY;
private:
intX,Y;
};
..."
Nameobj2=obj1;
."
须这样做:
如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,没有默认构造函数。
这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,
如果没有初始化列表,那么他将无法完成第一步,就会报错。
2、类成员中若有const修饰,必须在对象初始化的时候,给constintm赋值
当类成员中含有一个const对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化,
因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。
2)C++中提供初始化列表对成员变量进行初始化
语法规则
Constructor:
Contructor():
m1(v1),m2(v1,v2),m3(v3)
如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,
而没有默认构造函数,这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,
当类