TarnaC++语言从C到C++C++简介•80年代初由贝尔实验室的BjarneStroustrup设计和实现•1983年被正式命名为C++•1998年ANSI/ISO制定了C++国际标准•2003年推出了修定版本•C++一直在发展变化中…C++和C•C++包含整个C,C是建立C++的基础•C++是强类型语言,对类型检查严格•C++比C更丰富–支持面向对象–支持泛型编程–支持异常–运算符重载等第一个C++程序/*thefirstC++program*/#includeiostreamusingnamespacestd;//mainfunctionintmain(){coutHelloworld!endl;coutThisismyfirstC++program.\n;}第一个C++程序和第一个C程序的不同•可以选用g++编译器•源文件扩展名可以是.cpp.cc.C.cxx等•不再使用c中的头文件–如果要用,可以在c头文件名前加c•#includecxxxx•不再使用scanf/printf而是cin/cout•标准的C++头文件不再以.h结尾在C++中要使用命名空间•命名空间也称名字空间,即namespace–名字空间是一种描述逻辑分组的机制,如果一些声明按照某种准则在逻辑上属于同一集团,就可以将它们放入同一个名字空间,以表明这个事实。–防止命名冲突也是一个很重要的原因。一个人写的程序放到一个名字空间中也是一种可取的做法。•使用某个名字空间下的对象或函数:–namespace-name::member-name–::为域运算符,在此表名一种限定,一个范围定义命名空间•一个名字空间的成员必须采用如下的记法形式引入:namespacenamespace-name{//声明和定义}•我们不能在名字空间定义之外用加限定的语法形式为名字空间引入新成员•新成员的声明和定义是可以分开的•声明和定义分开后,编译器可以帮助捕捉到例如拼写或类型不匹配一类的错误。•一个名字空间也是一个作用域,一个程序越大,通过名字空间去描述其中逻辑上独立的各个部分也就越重要。•理想情况是,程序里的每个实体都属于某个可以识别的逻辑单位(模块),所以,一个非凡的程序里的每个声明都应该位于某个名字空间里,以此指明它在程序中所扮演的角色。使用命名空间•带限定词的名字。如果使用另外一个名字空间中的成员,需要加限定词,如:std::in•使用声明:usingstd::in•使用指令:usingnamespacestd;•无名名字空间–无名名字空间中的成员可以直接使用::访问C++中的结构、联合和枚举•C中的结构、联合和枚举类型名包含struct,union,enum,而C++则不•C++的结构中可以有函数,称为成员函数•C++的匿名联合union{intx;charc[4];};x=100;•C++的枚举不再是普通的整数类型,而是一种独立的类型,这个体现了C++强类型的特征C++的布尔类型bool•c99的bool是一种宏定义,而在c++中则是专门的一种数据类型bool•bool的值一般为true(逻辑真)和false(逻辑假)•和c一样,bool值本质上也是整数,true等于1,false等于0isLeap=true;intdays=28+isLeap;//2月份的天数•另外,可以将任何值赋值给bool类型的变量–以下4个值为false:•0‘\0’NULLfalse–其他一切值如果赋值给bool类型的变量都视为true•boolb=1;•b=true;•b=3.14;•b=“abcdef”C++运算符转换•C++中的运算符,可以用其他关键字转换x0&&y0可以写成x0andy0•下图为可以转换的列表C++中的函数•函数的参数表严格匹配,空参代表没有任何参数,void形参依然可以使用•不再支持C语言中的隐式声明方式,函数调用前必需先声明或定义•函数的返回类型int不能省略•函数可以重载–在同一作用域中,函数名相同,参数列表不同的函数可以存在若干个,其返回值任意–当出现重载函数时,使用函数指针显得有点问题,当给函数指针赋值时,指针的类型代表着具体的函数。–函数重载的实现是基于函数名的编译时改变–当程序跨越编译器或由其它语言调用重载函数时,函数名在编译时编译器不能对其改变,否则无法调用–extern“C”可以告诉编译器,像C语言那样进行编译处理。函数参数的哑元和默认值–哑元是一种没有参数名的参数,主要是为了函数间的区别以及向前兼容•函数的参数可以指定默认值,当调用时没有传参,就以默认值进行函数调用。•有默认值的形参必须靠右,声函数的参数支持哑元•明和定义分开时,默认值必需在声明中指定,定义中不再指定。C++中的内联函数•宏在C++中不提倡使用–宏存在着一些潜在的危险–C++中的面向对象不允许预处理器访问类的成员数据。也意味着宏函数不能用作类的成员函数。•内联函数保持了函数的所有特点,但在需要的地方会像宏一样展开,不需要调用函数的开销。•类中直接定义的函数自动被处理成内联函数,所以一般把内联函数放在头文件中。•inline是一种请求,实现方式取决于编译器,特别是当函数较大或是递归的时候。C++的内存分配•new/deleteint*p2=newint;//不保证是零int*p3=newint(100);int*p4=newint[5];deletep2;deletep3;delete[]p4;•定位分配charbuf[100]={};new(buf)int[25];–不存在定位分配所对应的delete运算,一旦buf释放,new所分配的空间也随即释放C++的引用reference•引用是另外一个变量的别名•引用的声明intiVal;int&iRef=iVal;•引用必须初始化,且必须用变量初始化。–不能写:int&a=10–可以写成constint&a=10;//常量引用•不可能有空引用,必须确保引用和一块合法的存储单元关联•当一个引用被初始化为指向一个对象,它就不能改变为指向另一个对象•引用是用指针来实现的在函数参数和返回值上的引用•函数的形参可以是引用类型•通过引用传递参数,称之为引用传递•用const来保护引用参数的传递•尽量使用引用传递参数•尽量使用引用代替指针•永远不要返回对局部变量的引用,除非局部变量是静态的或是在动态内存中分配的C++中的类型转换运算符•static_cast类型()–转换时做静态检查,即在编译时进行–void*到其他指针的转换•reinterpect_cast类型()–允许强转任何类型的指针–把整数强转成指针,指针强转成整数•const_cast类型()–去掉cv限制•dynamic_cast类型()–动态转换成员指针•成员指针是一种相对地址•结构体中的成员(包括变量和函数)的相对地址获取方式&结构类型名::成员•声明成员指针变量成员类型结构类型名::*指针变量名•通过成员指针访问结构成员结构变量.*指针变量名结构地址-*指针变量名C++之父给C程序员的建议•在C++中几乎不需要用宏–用const或enum定义明显的常量,用inline避免函数调用的额外开销,用模板去刻画一族函数或类型,用namespace去避免命名冲突•不要在你需要变量之前去声明,以保证你能立即对它进行初始化。•不要用malloc,new运算会做的更好•避免使用void*、指针算术、联合和强制,大多数情况下,强制都是设计错误的指示器。•尽量少用数组和C风格的字符串,标准库中的string和vector可以简化程序•更加重要的是,试着将程序考虑为一组由类和对象表示的相互作用的概念,而不是一堆数据结构和一些可以拨弄的二进制面向对象编程面向对象编程•万物皆对象•程序就是一组对象,对象之间通过发送消息互相通知做什么•每一个对象都有它自己的由其他对象构成的存储区•每一个对象有一个类型•一个特定类型的所有对象都能接收相同的消息类•类是用户定义的数据类型•在类中声明的变量和函数称为类的成员–变量称为数据成员(也叫成员变量)–函数称为成员函数(有时称为方法)•可以用类来声明变量(也称为实例)。每个实例是类的一个对象•定义类的实例可以称为类的实例化定义类•用struct定义类–成员默认为公开•用class定义类–成员默认为私有•类中成员的作用域–private–protected–public构造并使用对象•定义类Time并使用–成员变量时分秒–成员函数显示滴答…•使用标准库中的类string构造对象–=+=+====!=–size()length()find()str[i]s.c_str(转换成c风格,返回char*)–其他成员函数构造函数•构造函数–和类名相同–没有返回值类型–只在建立对象的时候被自动调用一次–调用构造函数的主要目的是初始化对象•一个对象的创建过程:–分配内存空间–初始化成员变量,如果成员是对象,构造他–调用构造函数•默认的空参构造函数构造函数的使用•构造函数重载–构造函数也是函数,拥有重载的特征–重载的构造函数在构造对象时根据参数自动选择•利用参数默认值简化构造函数–构造函数也拥有函数参数默认值的特性–使用默认值可以减少构造函数的个数•构造函数的初始化列表–初始化列表可以让构造函数在调用之前进行初始化工作–如果类的成员变量是const或引用类型,使用初始化列表是不二选择•实践中,类的声明和定义是分开的–请试着将写的类分成头文件和实现两部分调用对象的成员函数与this指针•一个对象占多大空间呢?•成员函数保存在哪儿?•调用成员函数时,会自动传this指针•this指针是指向当前对象的指针•在成员函数中,可以将this指针当参数传递,也可以返回this指针,或返回通过this指针拿到的对象const对象和const成员函数•成员函数可以声明成const函数(声明后加const)•对于const对象,只能调用const成员函数•Const函数和非const函数可以形成重载•对于非const对象的函数调用优先选择非const成员函数•对于类中的mutable数据成员,可以被const成员函数修改析构函数•与类名同,但名称前有一个~•一个类只有一个析构•析构没有参数,没有返回值•在一个对象释放前调用。释放可能是主动的,也可能是被动的。•一个对象的析构函数只调用一次,但语法上允许多次调用•默认析构函数–何时需要自定义析构呢?堆中构造和释放对象•new/delete构造和释放对象•使用C风格分配空间构造对象–malloc/free•new和malloc的不同–new在分配空间后会比malloc多做三件事•如果对象成员又是对象,自动构造此对象•自动调用构造函数•自动处理类型转换•delete和free的区别–delete在释放对象之前会调用析构函数拷贝构造函数•类会提供默认的拷贝构造函数–默认的拷贝构造函数会完成所有成员的逐个复制•拷贝构造的调用时机:–函数值传递时–函数返回时–用同类型的对象初始时•何时需要自定义拷贝构造函数?–类中有指针(或引用)成员时–希望自定义对象的拷贝过程时•使用匿名对象简化编程静态成员•静态成员变量的初始化需要在类外完成•静态成员不属于具体的某个对象,而属于整个类•所有对象共享本类中的静态成员•静态成员最好直接通过类名::成员来访问和调用•静态成员函数中没有this指针运算符重载输入和输出•cout对象被编译器解释为:–cout.operator(对象)或–operator(cout,对象)•cin对象被编译器解释为–cin.operator(对象)或–operator(cin,对象)友元函数•将函数声明成友元,以获得额外的权利–friend•一个成员函数的三项事情:–1)访问类中的私用部分–2)函数位于类的作用域中–3)必须经由对象调用(拥有this指针)•一个静态成员函数只有前两种性质,而友员函数只拥有第一个性质。双目运算符重载•+、-、*、/…•、、=、=、