C C++ 是干什么的


1简单的C++ Hello World!

#include"iostream"usingnamespacestd;intmain(){cout<<"HelloWorld!\n";//<<endl;cout<<"HelloWorld!"<<endl;return0;}编译运行:chunli@Linux:~/c++$g++main.cpp&&./a.outHelloWorld!HelloWorld!chunli@Linux:~/c++$



2面向对象的认识:

求圆的面积,过程方法

#include"iostream"usingnamespacestd;intmain(){doubler=0;doubles=0;cout<<"请输入圆的半径:";//<<endl;cin>>r;s=3.1415926*r*r;cout<<"圆的面积是:"<<s<<endl;return0;}编译:chunli@Linux:~/c++$g++main.cpp&&./a.out请输入圆的半径:10圆的面积是:314.159


求圆的面积,面向对象方法

#include"iostream"usingnamespacestd;//类是一个数据类型,(固定大小内存块的别名);//定义一个类,是一个抽象的概念,不会给你分配内存//用数据类型定义变量的时候,才会分配内存classMyCicle{public:doublem_s;doublem_r;voidset_R(doubler){m_r=r;}doublegets(){return3.1415926*m_r*m_r;}};intmain(){MyCiclemy1;doubler;cout<<"请输入圆的半径:";cin>>r;my1.set_R(r);cout<<"圆的面积是:"<<my1.gets()<<endl;return0;}编译运行:chunli@Linux:~/c++$g++main.cpp&&./a.out请输入圆的半径:11圆的面积是:380.133


【经典】初学者易犯错误:

#include"iostream"usingnamespacestd;classMyCicle{public:doubler;doubles=3.14*r*r;};intmain(){MyCiclemy1;cout<<"请输入圆的半径:";cin>>my1.r;cout<<"圆的面积是:"<<my1.s<<endl;return0;}编译运行:Lchunli@Linux:~/c++$g++-std=c++11main.cpp&&./a.out请输入圆的半径:10圆的面积是:0



namespace 1,标准用法:

因为iostream中没有引入标准std,需要程序员手工写

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;intmain(){cout<<"HelloWorld!"<<endl;return0;}编译运行:chunli@Linux:~/c++$g++main.cpp&&./a.outHelloWorld!


namespace 2,实际用法:

如果不写 using namespace std ,那么需要显式的引入std

chunli@Linux:~/c++$catmain.cpp#include"iostream"//usingnamespacestd;intmain(){std::cout<<"HelloWorld!"<<std::endl;return0;}chunli@Linux:~/c++$g++main.cpp&&./a.outHelloWorld!




自定义namespace

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;namespacenamespaceA{inta;}namespacenamaspaceB{inta;namespacenamaspaceC{inta;}}intmain(){usingnamespacenamespaceA;a=10;cout<<a<<endl;return0;}编译运行:chunli@Linux:~/c++$g++main.cpp&&./a.out10



两个namespace中含有同样的变量,编译不通过

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;namespacenamespaceA{inta;}namespacenamespaceB{inta;namespacenamespaceC{inta;}}intmain(){usingnamespacenamespaceA;usingnamespacenamespaceB;a=10;cout<<a<<endl;return0;}chunli@Linux:~/c++$g++main.cpp&&./a.outmain.cpp:Infunction‘intmain()’:main.cpp:24:2:error:referenceto‘a’isambiguousa=10;^可以看到不明确a是哪一个




显式的引用不同namespace中的值

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;namespacenamespaceA{inta;}namespacenamespaceB{inta;namespacenamespaceC{inta;}}intmain(){usingnamespacenamespaceA;usingnamespacenamespaceB;namespaceA::a=10;namespaceB::a=20;cout<<namespaceA::a<<endl;cout<<namespaceB::a<<endl;return0;}chunli@Linux:~/c++$g++main.cpp&&./a.out1020


使用嵌套的namespace

#include"iostream"usingnamespacestd;namespacenamespaceB{inta;namespacenamespaceC{structTeacher{intage;};}}intmain(){usingnamespacenamespaceB::namespaceC;Teachert1;t1.age=10;cout<<t1.age<<endl;return0;}编译:chunli@Linux:~/c++$g++main.cpp&&./a.out10

=============================================================================

C++与C的区别:


1

2register类型增强

chunli@Linux:~/c++$cat123.c#include<stdio.h>intmain(){registerinta=0;printf("%p\n",&a);return0;}C语言编译不通过:chunli@Linux:~/c++$gcc123.c&&./a.out123.c:Infunction‘main’:123.c:5:2:error:addressofregistervariable‘a’requestedprintf("%p\n",&a);^C++编译通过:chunli@Linux:~/c++$g++123.c&&./a.out0x7ffe7ac2cc3c


C语言缺陷,C++修复

chunli@Linux:~/c++$cat123.c#include<stdio.h>f(i){printf("i=%d\n",i);}g(){return5;}intmain(){f(10);printf("%d\n",g());printf("%d\n",g(1,2,3,4));return0;}C语言编译OKchunli@Linux:~/c++$gcc123.c&&./a.outi=1055C++编译报错:chunli@Linux:~/c++$g++123.c&&./a.out123.c:2:2:error:expectedconstructor,destructor,ortypeconversionbefore‘(’tokenf(i)^123.c:6:3:error:ISOC++forbidsdeclarationof‘g’withnotype[-fpermissive]g()^


C++对C的加强:

1 namespace命名空间


1 C++命名空间基本常识

所谓namespace,是指标识符的各种可见范围。C++标准程序库中的所有标识符都被定义于一个名为std的namespace中。

一 :<iostream>和<iostream.h>格式不一样,前者没有后缀,实际上,在你的编译器include文件夹里面可以看到,二者是两个文件,打开文件就会发现,里面的代码是不一样的。后缀为.h的头文件c++标准已经明确提出不支持了,早些的实现将标准库功能定义在全局空间里,声明在带.h后缀的头文件里,c++标准为了和C区别开,也为了正确使用命名空间,规定头文件不使用后缀.h。 因此,

1)当使用<iostream.h>时,相当于在c中调用库函数,使用的是全局命名空间,也就是早期的c++实现;

2)当使用<iostream>的时候,该头文件没有定义全局命名空间,必须使用namespace std;这样才能正确使用cout。

二: 由于namespace的概念,使用C++标准程序库的任何标识符时,可以有三种选择:

1、直接指定标识符。例如std::ostream而不是ostream。完整语句如下: std::cout << std::hex << 3.4 << std::endl;

2、使用using关键字。 using std::cout; using std::endl; using std::cin; 以上程序可以写成 cout << std::hex << 3.4 << endl;

3、最方便的就是使用using namespace std; 例如: using namespace std;这样命名空间std内定义的所有标识符都有效(曝光)。就好像它们被声明为全局变量一样。那么以上语句可以如下写: cout <<hex << 3.4 << endl;因为标准库非常的庞大,所以程序员在选择的类的名称或函数名 时就很有可能和标准库中的某个名字相同。所以为了避免这种情况所造成的名字冲突,就把标准库中的一切都被放在名字空间std中。但这又会带来了一个新问 题。无数原有的C++代码都依赖于使用了多年的伪标准库中的功能,他们都是在全局空间下的。所以就有了<iostream.h> 和<iostream>等等这样的头文件,一个是为了兼容以前的C++代码,一个是为了支持新的标准。命名空间std封装的是标准程序库的名称,标准程序库为了和以前的头文件区别,一般不加".h"





4.2 “实用性”增加

#include"iostream"usingnamespacestd;//C语言中的变量都必须在作用域开始的位置定义!!//C++中更强调语言的“实用性”,所有的变量都可以在需要使用时再定义。intmain11(){inti=0;printf("ddd");intk;system("pause");return0;}


4.3 register关键字增强

//register关键字请求编译器让变量a直接放在寄存器里面,速度快//在c语言中register修饰的变量不能取地址,但是在c++里面做了内容/*//1register关键字的变化register关键字请求“编译器”将局部变量存储于寄存器中C语言中无法取得register变量地址在C++中依然支持register关键字C++编译器有自己的优化方式,不使用register也可能做优化C++中可以取得register变量的地址//2C++编译器发现程序中需要取register变量的地址时,register对变量的声明变得无效。//3早期C语言编译器不会对代码进行优化,因此register变量是一个很好的补充。*/intmain22(){registerinta=0;printf("&a=%x\n",&a);system("pause");return0;}


4.4变量检测增强

/*在C语言中,重复定义多个同名的全局变量是合法的在C++中,不允许定义多个同名的全局变量C语言中多个同名的全局变量最终会被链接到全局数据区的同一个地址空间上intg_var;intg_var=1;C++直接拒绝这种二义性的做法。*/intmain(intargc,char*argv[]){printf("g_var=%d\n",g_var);return0;}


4.5 struct类型加强

struct类型的加强:

C语言的struct定义了一组变量的集合,C编译器并不认为这是一种新的类型

C++中的struct是一个新类型的定义声明

structStudent{charname[100];intage;};intmain(intargc,char*argv[]){Students1={"wang",1};Students2={"wang2",2};return0;}



4.6 C++中所有的变量和函数都必须有类型

/*C++中所有的变量和函数都必须有类型C语言中的默认类型在C++中是不合法的函数f的返回值是什么类型,参数又是什么类型?函数g可以接受多少个参数?*///更换成.cpp试试f(i){printf("i=%d\n",i);}g(){return5;}intmain(intargc,char*argv[]){f(10);printf("g()=%d\n",g(1,2,3,4,5));getchar();return0;}





【总结】:

/*

在C语言中

int f( );表示返回值为int,接受任意参数的函数

int f(void);表示返回值为int的无参函数

在C++中

int f( );和int f(void)具有相同的意义,都表示返回值为int的无参函数

*/


C++更加强调类型,任意的程序元素都必须显示指明类型




4.2-4.6属于语法级别的增强。

4.7新增Bool类型关键字

/*C++中的布尔类型C++在C语言的基本类型系统之上增加了boolC++中的bool可取的值只有true和false理论上bool只占用一个字节,如果多个bool变量定义在一起,可能会各占一个bit,这取决于编译器的实现true代表真值,编译器内部用1来表示false代表非真值,编译器内部用0来表示bool类型只有true(非0)和false(0)两个值C++编译器会在赋值时将非0值转换为true,0值转换为false*/intmain(intargc,char*argv[]){inta;boolb=true;printf("b=%d,sizeof(b)=%d\n",b,sizeof(b));b=4;a=b;printf("a=%d,b=%d\n",a,b);b=-4;a=b;printf("a=%d,b=%d\n",a,b);a=10;b=a;printf("a=%d,b=%d\n",a,b);b=0;printf("b=%d\n",b);system("pause");return0;}







4.8三目运算符功能增强

1三目运算符在C和C++编译器的表现

intmain(){inta=10;intb=20;//返回一个最小数并且给最小数赋值成3//三目运算符是一个表达式,表达式不可能做左值(a<b?a:b)=30;printf("a=%d,b=%d\n",a,b);system("pause");return0;}




2结论

1)C语言返回变量的值 C++语言是返回变量本身

C语言中的三目运算符返回的是变量值,不能作为左值使用

C++中的三目运算符可直接返回变量本身,因此可以出现在程序的任何地方

2)注意:三目运算符可能返回的值中如果有一个是常量值,则不能作为左值使用

(a < b ? 1 : b )= 30;

3)C语言如何支持类似C++的特性呢?

====>当左值的条件:要有内存空间;C++编译器帮助程序员取了一个地址而已

思考:如何让C中的三目运算法当左值呢?






C++ bool类型

只要是非0数字赋予bool类型,全部为true

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;intmain(){boolb1=true;cout<<sizeof(b1)<<endl;b1=10;cout<<b1<<endl;b1=-10;cout<<b1<<endl;b1=0;cout<<b1<<endl;return0;}chunli@Linux:~/c++$g++main.cpp&&./a.out1110chunli@Linux:~/c++$


C++ 对三目运算符的增强:

chunli@Linux:~/c++$catc.c#include<stdio.h>intmain(){inta=10;intb=20;//在C语言中表达式返回值,返回变量的本身//在++语言中返回变量本身(a<b?a:b)=30;printf("%d\n",a);printf("%d\n",b);return0;}chunli@Linux:~/c++$gccc.c&&./a.outc.c:Infunction‘main’:c.c:6:17:error:lvaluerequiredasleftoperandofassignment(a<b?a:b)=30;^chunli@Linux:~/c++$g++c.c&&./a.out3020





在C语言中如何实现在C++中编译器的效果

C++编译器帮程序员完成了刚才我们的动作

chunli@Linux:~/c++$catc.c#include<stdio.h>intmain(){inta=10;intb=20;*(a<b?&a:&b)=30;printf("%d\n",a);printf("%d\n",b);return0;}chunli@Linux:~/c++$gccc.c&&./a.out3020chunli@Linux:~/c++$g++c.c&&./a.out3020



C++ const 基础

#include"iostream"usingnamespacestd;intmain(){constinta=10;intconstb=11;//与上面的一样constint*c;//指针指向的内存区域内的数值不能修改int*constd;//指针不能乱指constint*conste;//只读指针return0;}


const C C++语言中的冒牌货

1,C语言中的const真是个冒牌货

chunli@Linux:~/c++$catc.c#include<stdio.h>intmain(){constinta=10;int*p=(int*)&a;*p=20;printf("%d\n",a);return0;}chunli@Linux:~/c++$gccc.c&&./a.out20


2,C++语言中的const真是真货

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;intmain(){constinta=10;int*p=NULL;p=(int*)&a;*p=20;cout<<a<<endl;cout<<*p<<endl;return0;}chunli@Linux:~/c++$g++-Wallmain.cpp&&./a.out1020


const 与define

GCC支持这种写法,微软的不支持

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;intmain(){inta=10;intb=30;intarr[a+b];cout<<sizeof(arr)/sizeof(int)<<endl;return0;}chunli@Linux:~/c++$g++-Wallmain.cpp&&./a.out40



C++编译器cosnt与宏定义 相似之处

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;#definea20intmain(){//inta=10;intb=30;intarr[a+b];cout<<sizeof(arr)/sizeof(int)<<endl;return0;}chunli@Linux:~/c++$g++-Wallmain.cpp&&./a.out50


宏定义作用范围

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;voidfun1(){#definea20cout<<"HelloWorld!"<<endl;}voidfun2(){cout<<a<<endl;}intmain(){fun1();fun2();return0;}chunli@Linux:~/c++$g++-Wallmain.cpp&&./a.outHelloWorld!20


取消宏定义

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;voidfun1(){#definea20cout<<"HelloWorld!"<<endl;#undefa//取消宏定义a//#undef//取消所有宏定义}voidfun2(){cout<<a<<endl;}intmain(){fun1();fun2();return0;}chunli@Linux:~/c++$g++-Wallmain.cpp&&./a.outmain.cpp:Infunction‘voidfun2()’:main.cpp:13:10:error:‘a’wasnotdeclaredinthisscopecout<<a<<endl;^




【引用】


1,基础知识,两个变量的地址是一样的

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;intmain(){inta=10;int&b=a;b=20;cout<<a<<endl;cout<<&a<<endl;cout<<&b<<endl;return0;}chunli@Linux:~/c++$g++-Wallmain.cpp&&./a.out200x7ffec647cc940x7ffec647cc94这就是传说中的引用,不能用C语言去思考



1,定义一个引用,而没有引用值,编译报错;

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;intmain(){inta=10;cout<<a<<endl;int&b;return0;}chunli@Linux:~/c++$g++-Wallmain.cpp&&./a.outmain.cpp:Infunction‘intmain()’:main.cpp:7:7:error:‘b’declaredasreferencebutnotinitializedint&b;^




引用的实际应用,当函数参数

引用当函数参数不需要初始化

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;voidfun1(int&a,int&b){a=a^b;b=a^b;a=a^b;}voidfun2(int*a,int*b){*a=*a^*b;*b=*a^*b;*a=*a^*b;}intmain(){intvar1=10;intvar2=20;cout<<var1<<""<<var2<<endl;fun1(var1,var2);cout<<var1<<""<<var2<<endl;fun2(&var1,&var2);cout<<var1<<""<<var2<<endl;return0;}chunli@Linux:~/c++$g++-Wallmain.cpp&&./a.out102020101020chunli@Linux:~/c++$


复杂数据类型与引用;

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;structTeacher{charname[64];intage;};voidfun1(Teacher*p){cout<<p->age<<endl;p->age=11;}voidfun2(Teacher&p){cout<<p.age<<endl;p.age=22;}voidfun3(Teacherp){cout<<p.age<<endl;p.age=33;}intmain(){Teachert1;t1.age=20;fun1(&t1);cout<<"1"<<t1.age<<endl;fun2(t1);cout<<"2"<<t1.age<<endl;fun3(t1);cout<<"3"<<t1.age<<endl;return0;}chunli@Linux:~/c++$g++-Wallmain.cpp&&./a.out201111122222322chunli@Linux:~/c++$


结构体的引用类型实质

可以看出与指针很像

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;structTeacher{char&c;};intmain(){cout<<sizeof(structTeacher)<<endl;return0;}chunli@Linux:~/c++$g++-Wallmain.cpp&&./a.out8




引用的本质,看图

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;voidfun1(int&a){a=10;}voidfun2(int*a){*a=20;}intmain(){intvar=0;fun1(var);cout<<var<<endl;fun2(&var);cout<<var<<endl;return0;}chunli@Linux:~/c++$g++-Wallmain.cpp&&./a.out1020




引用的难点:

返回引用数据类型的函数,用什么数据类型来接?

1,用普通变量来接,相当于数值的传递

2,用引用类型数据来接,相当于地址的传递(危险),返回的地址是已经被析构的

GCC会有警告

VS不会有警告

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;int&fun1(){inta=10;returna;}intmain(){inta=fun1();cout<<a<<endl;int&b=fun1();cout<<b<<endl;return0;}chunli@Linux:~/c++$g++main.cpp&&./a.outmain.cpp:Infunction‘int&fun1()’:main.cpp:5:6:warning:referencetolocalvariable‘a’returned[-Wreturn-local-addr]inta=10;^1010


函数返回应用类型,变量是全局生命周期

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;inta=20;int&fun1(){returna;}intmain(){inta=fun1();cout<<a<<endl;int&b=fun1();cout<<b<<endl;return0;}chunli@Linux:~/c++$g++main.cpp&&./a.out2020



函数当左值,注意变量的生命周期

chunli@Linux:~/c++$catmain.cpp#include"iostream"usingnamespacestd;inta=20;int&fun1(){cout<<"infun1"<<a<<endl;returna;}intmain(){//当左值fun1()=100;cout<<"infun2"<<a<<endl;//当右值inta=fun1();return0;}chunli@Linux:~/c++$g++main.cpp&&./a.outinfun120infun2100infun1100