目录
前言
1.什么是C++
2.命名空间
2.1命名空间定义
2.2命名空间的使用
3.C++输入&输出
4.缺省参数
4.1缺省参数概念
4.2缺省参数分类
5.函数重载
5.1函数重载概念
6.引用
6.1引用概念
6.2引用特性
6.3常引用
6.4使用场景
6.5引用和指针的比较
6.6引用和指针的区别
前言
1.什么是C++C++是在C的基础之上,容纳进去了面向对象编程思想,并增加了许多有用的库,以及编程范式等。熟悉C语言之后,对C++学习有一定的帮助,本篇博客主要目标:
1. 补充C语言语法的不足,以及C++是如何对C语言设计不合理的地方进行优化的,比如:作用域方面、IO方面、函数方面、指针方面、宏方面等。
2. 为后续类和对象学习打基础。
C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机, 20世纪80年代, 计算机界提出了OOP(object oriented programming:面向对象)思想,支持面向对象的程序设计语言应运而生。
1982年,Bjarne Stroustrup博士在C语言的基础上引入并扩充了面向对象的概念,发明了一种新的程序语言。为了表达该语言与C语言的渊源关系,命名为C++。因此:C++是基于C语言而产生的,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计。
2.命名空间
#include#include int rand = 10 ; // C 语言没办法解决类似这样的命名冲突问题,所以 C++ 提出了 namespace 来解决 int main () { printf ( "%d\n" , rand ); return 0 ; } // 编译后后报错: error C2365: “rand”: 重定义;以前的定义是 “ 函数 ”
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本化,以避免命名冲突或名字污染,namespace关键字的的出现就是针对这种问题的。
如以上的代码,rand在
2.1命名空间定义
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{ }即可,{}
中即为命名空间的成员。
// bit 是命名空间的名字,一般开发中是用项目名字做命名空间名。 namespace bit { // 命名空间中可以定义变量 / 函数 / 类型 int rand = 10 ; int Add ( int left , int right ) { return left + right ;}
struct Node { struct Node * next ; int val ; }; } //2. 命名空间可以嵌套 // test.cpp namespace N1 { int a ; int b ; int Add ( int left , int right ) { return left + right ; } namespace N2 { int c ; int d ; int Sub ( int left , int right ) { return left - right ; } } } //3. 同一个工程中允许存在多个相同名称的命名空间 , 编译器最后会合成同一个命名空间中。 // ps :一个工程中的 test.h 和上面 test.cpp 中两个 N1 会被合并成一个 namespace N1 { int Mul ( int left , int right ) { return left * right ; } }
命名空间在今后工作更加重要,比如现在公司在制作一个大型项目,一般是会再分为几个项目组各司其职之后再汇合起来,那么我怎么知道另外一个项目组会用什么函数名?等到最后汇总的时候就一定会出现很多命名冲突的报错
std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
2.2命名空间的使用
命名空间的使用有三种方式:
加命名空间名称及作用域限定符
int main () { printf ( "%d\n" , N::a ); return 0 ; } 如上代码的 N::的作用就是指定编译器去访问N这个命名空间 而在作用域限定符前面空间名称若为空则默认全局
使用using将命名空间中某个成员引入
using N::b ; int main () { printf ( "%d\n" , N::a ); printf ( "%d\n" , b ); return 0 ; } 使用using N::b 的含义就是将命名空间的N中的b给释放出来,在以后的代码中便能直接访问,但是这样也便存在命名冲突的问题 所以一般建议可以释放那些常用的,然后在编程命名时就避免与这些常用名冲突
使用using namespace 命名空间名称 引入
using namespce N ; int main () { printf ( "%d\n" , N::a ); printf ( "%d\n" , b ); Add ( 10 , 20 ); return 0 ; }使用了using namespace N 之后 也就意味着你将N这个命名空间都释放了,那这样也就没有限定到了,一般此 *** 作用于我们自己平时练习,直接释放标准库的命名空间std
std命名空间的使用惯例:
std是C++标准库的命名空间,如何展开std使用更合理呢?
1. 在日常练习中,建议直接using namespace std即可,这样就很方便。
2. using namespace std展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对 象/函数,就存在冲突问题。该问题在日常练习中很少出现,但是项目开发中代码较多、规模大,就很容易出现。所以建议在项目开发中使用,像std::cout这样使用时指定命名空间 + using std::cout展开常用的库对象/类型等方式。
3.C++输入&输出
来吧 每一门编程语言的第一个程序:Hello World
#include// std 是 C++ 标准库的命名空间名, C++ 将标准库的定义实现都放到这个命名空间中 using namespace std ; int main () { cout << "Hello world!!!" << endl ; return 0 ; }
以上代码便是我们的第一个C++代码,对于输入和输出的代码,在目前的入门没办法十分透彻地去解释代码的底层逻辑,因为涉及到许多C++的一些语法知识,所以在我们这篇入门博客就先简单地了解一下,毕竟输入输出这两功能是我们编写程序时必不可少的嘛
1. 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件
以及按命名空间使用方法使用std。
2. cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含<
iostream >头文件中。
3. <<是流插入运算符,>>是流提取运算符。
4. 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。C++的输入输出可以自动识别变量类型。
5. 实际上cout和cin分别是ostream和istream类型的对象,>>和<<也涉及运算符重载等知识,这些知识我们我们后续才会学习,所以我们这里只是简单学习他们的使用。后面我们还有会更深入的学习IO流用法及原理。
#includeusing namespace std ; int main () { int a ; double b ; char c ; // 可以自动识别变量的类型 cin >> a ; cin >> b >> c ; cout << a << endl ; cout << b << " " << c << endl ; return 0 ; }
cout和cin比起我们C语言的scanf和printf方便在于它能自动识别数据类型,不需要我们去声明,但是也有不太方便的就是但你要输出字符串与数据混合时就真不太方便,以及要限定小数点后几位时也比较复杂(这里就不多做介绍平时也比较少用)而因为我们的C++是兼容C语言的,所以我们可以各取所长,哪个方便用哪个
4.缺省参数 4.1缺省参数概念
缺省参数是声明或者定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
void Func ( int a = 0 ) { cout << a << endl ; } int main () { Func (); // 没有传参时,使用参数的默认值 Func ( 10 ); // 传参时,使用指定的实参 return 0 ; }
4.2缺省参数分类
全缺省参数
void Func ( int a = 10 , int b = 20 , int c = 30 ) { cout << "a = " << a << endl ; cout << "b = " << b << endl ; cout << "c = " << c << endl ; }
半缺省参数
void Func ( int a , int b = 10 , int c = 20 ) { cout << "a = " << a << endl ; cout << "b = " << b << endl ; cout << "c = " << c << endl ; }
注意:
1.半缺省参数必须从右往左依次给出,不能间隔着给
2.缺省参数不能在函数的声明和定义中同时出现
//a.h void Func ( int a = 10 ); // a.cpp void Func ( int a = 20 ) {} // 注意:如果生命与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该 用那个缺省值。
3.缺省值必须是常量或者全局变量
4.C语言不支持
5.函数重载
自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重
载了。
比如:以前有一个笑话,国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个
是男足。前者是“谁也赢不了!”,后者是“谁也赢不了!”
5.1函数重载概念
函数重载:是函数的一种特殊情况,C++允许在同一个作用域中声明几个同名的功能类似的函数,这些同名函数的形参列表(参数个数 或 参数类型 或参数顺序)不同,常用来处理实现功能类似数据类型不同的问题。
#includeusing namespace std ; // 1 、参数类型不同 int Add ( int left , int right ) { cout << "int Add(int left, int right)" << endl ; return left + right ; } double Add ( double left , double right ) { cout << "double Add(double left, double right)" << endl ; return left + right ; } // 2 、参数个数不同 void f () { cout << "f()" << endl ; } void f ( int a ) { cout << "f(int a)" << endl ; } // 3 、参数类型顺序不同 void f ( int a , char b ) { cout << "f(int a,char b)" << endl ; } void f ( char b , int a ) { cout << "f(char b, int a)" << endl ; } int main () { Add ( 10 , 20 ); Add ( 10.1 , 20.2 ); f (); f ( 10 ); f ( 10 , 'a' ); f ( 'a' , 10 ); return 0 ; }
6.引用 6.1引用概念
引用不是新定义一个变量,而是给已存在的变量取一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用一块内存空间。
比如:李逵,在家称为“铁牛”,江湖上人称“黑旋风”
使用格式:
类型& 引用变量名(对象名)= 引用实体;
void TestRef () { int a = 10 ; int & ra = a ; //<==== 定义引用类型 printf ( "%p\n" , & a ); printf ( "%p\n" , & ra ); }
注意:引用类型必须和引用实体是同种类型的
6.2引用特性1.引用在定义时必须初始化
2.一个变量可以有多个引用
3.引用一旦引用了一个实体,再不能引用其他对象
void TestRef () { int a = 10 ; // int& ra; // 该条语句编译时会出错 int & ra = a ; int & rra = a ; printf ( "%p %p %p\n" , & a , & ra , & rra ); }
6.3常引用
void TestConstRef () { const int a = 10 ; //int& ra = a; // 该语句编译时会出错, a 为常量 const int & ra = a ; // int& b = 10; // 该语句编译时会出错, b 为常量 const int & b = 10 ; double d = 12.34 ; //int& rd = d; // 该语句编译时会出错,类型不同 const int & rd = d ; }
在使用引用时要注意不能对数据的权限进行扩大,我们知道,权限只能缩小不能扩大
像第一段代码
变量a被const修饰后就只能读不能修改,而假如我们直接引用的话,就给了我们修改它的权限,这样就会编译报错,所以我们只能进行权限平移,在引用前也加const修饰符。第二段代码同理,常数也只能读不能修改。
而第三段代码就涉及到一些另外的知识
double d = 12.34 ; int rd = d; 以上两列代码最后输出 rd 的结果是什么?-------->12 而这个过程中就会发生截断(在以往的博客有介绍此知识)而截断其实是会临时开辟了一个空间临时拷贝出一个临时变量的,不是直接去截断 *** 作d这个变量本身,而临时变量具有常性,也就是只能读不能读写,所以我们引用时也需要加上const修饰
6.4使用场景
1.做参数
void Swap ( int & left , int & right ) { int temp = left ; left = right ; right = temp ; }
用此 *** 作我们在调用函数的时候就不需要使用指针了
2.做返回值
int & Count () { static int n = 0 ; n ++ ; // ... return n ; }
下面代码输出的结果是什么?为什么?
int & Add ( int a , int b ) { int c = a + b ; return c ; } int main () { int & ret = Add ( 1 , 2 ); Add ( 3 , 4 ); cout << "Add(1, 2) is :" << ret << endl ; return 0 ; }
注意:
1.函数运行时,系统需要给该函数开辟独立的栈空间,用来保存该函数的形参、局部变量以及一些寄存器信息
2.函数运行结束后,该函数对应的栈空间就被系统回收了
3.空间被回收指该空间暂时不能被使用,但是内存还在;比如:上课要申请教室,上完课后教室归还给学校,但是教室本身还在,不能说归还后教室就没有了。
综上所述:如果函数返回时,出了函数作用域后,返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统了,那么必须使用你传值返回。
6.5引用和指针的比较
以值作为参数或者返回类型,在传参和返回期间,函数不会直接传递实参或者将变量直接返回,而是传递实参或者返回变量的一份临时拷贝,因此用值作为参数或者作为返回值类型,效率是十分低下的,尤其当参数或者返回值类型非常大时,效率就更地下。
6.6引用和指针的区别
1.引用在概念上是定义一个变量的别名,指针则是储存一个变量的地址
2.引用在定义时必须初始化,指针则没有要求
3.引用在定义时引用了一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同一类型的实体
4.没有NULL引用,但是有NULL指针
5.在sizeof中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占的字节个数(32位平台下占4字节)
6.引用自加则为引用的变量加1,指针自加则为指针向后便宜一个类型大小
7.有多级指针但是没有多级引用
8.引用比指针用起来更加安全
9.访问实体方式不同,指针需要显式解引用,引用则编译器自己处理
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)