当前位置: 首页 > news >正文

C++基础:(二)C++入门知识介绍(下)

目录

前言

一、C++输入和输出

二、缺省参数

三、函数重载

四、引用

4.1  引用的概念和定义

4.2  引用的特性

4.3  引用的使用

4.4  const引用

4.5  指针和引用的关系

五、inline

六、nullptr

总结


前言

        在C++编程语言中,函数重载、输入输出操作、缺省参数以及引用机制是提升代码灵活性和效率的核心特性。函数重载允许开发者通过同名函数处理不同类型或数量的参数,简化接口设计;而C++的输入输出流(如cincout)为数据交互提供了类型安全且可扩展的解决方案。缺省参数进一步增强了函数的通用性,减少了冗余代码的编写。引用机制则避免了不必要的拷贝开销,同时支持更直观的语义操作。这些特性共同构成了现代C++高效、可维护的编程范式,为开发者提供了强大的工具集。深入理解其原理与应用,能够显著提升程序的性能和可读性。那么话不多说,下面那就让我们正式开始吧!


一、C++输入和输出

1.  <iostream>是Input Output Stream的缩写,是标准的输入、输出流库,定义了标准的输入、输出对象。

2.  std::cin 是istream类的对象,它主要面向窄字符(Narrow Characters(of type char))的标准输入输出流。

3.  std::cout 是ostream类的对象,它主要面向窄字符的标准输出流。

4.  std::endl 是一个函数,流插入输出时,相当于一个换行字符加刷新缓冲区。

5.  << 流插入运算符,>>流提取运算符。(C语言还用这两个运算符做位运算左移/右移)。

6.  使用C++输入输出更加方便,不需要像 printf / scanf 输入输出时那样,需要手动指定格式,C++的输入输出可以自动识别变量类型(本质上是通过函数重载实现的,这个以后会讲到),其实最重要的是C++的流能够更好地支持自定义类型对象的输入输出。

7.  IO流涉及类和对象,运算符重载、继承等很多面向对象的知识,这些知识我们还没有讲解,所以这里我们只能简单认识一下C++IO流的用法,后面我们会有专门的一篇博客来详细讲解IO库。

8.  cout / cin / endl 等都属于C++标准库,C++标准库都放在一个叫做std(standard)的命名空间中,所以要通过命名空间的使用方式去用他们。

9.  一般日常练习中我们可以用 using namespace std ,但在实际项目的开发中是不建议使用的。

10.  在下面的代码中我们没有包含<stdio.h>,也可以使⽤printf和scanf,在包含<iostream>时间接包含了。vs系列编译器是这样的,但如果使用的是其他编译器则可能会报错。

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;int main()
{int a = 0;double b = 0.1;char c = 'x';cout << a << " " << b << " " << c << endl;std::cout << a << " " << b << " " << c << std::endl;scanf("%d%lf", &a, &b);printf("%d %lf\n", a, b);// 可以⾃动识别变量的类型cin >> a;cin >> b >> c;cout << a << endl;cout << b << " " << c << endl;return 0;
}

        在这里我再额外补充一个小的知识点:在如大量输入输出的竞赛题中等I/O需求比较高的地方,我们可以加上如下的代码来提高I/O效率:

#include<iostream>
using namespace std;int main()
{// 在io需求⽐较⾼的地⽅,如部分⼤量输⼊的竞赛题中,加上以下3⾏代码// 可以提⾼C++IO效率ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);return 0;
}

        它们的主要作用是消除 C++ 标准流与 C 标准流之间的同步,从而提高程序的输入输出效率。

1.  ios_base::sync_with_stdio(false);

        关闭 C++ 标准流(cin/cout)与 C 标准流(stdin/stdout)的同步机制;

        默认情况下,C++ 流与 C 流是同步的,这保证了两种流可以混合使用(如交替使用coutprintf);

        关闭同步后,C++ 流的操作效率会显著提升,但不能再混合使用 C++ 流和 C 流的输入输出函数。

2.  cin.tie(nullptr);

        解除cincout的绑定关系;

        默认情况下,cin会与cout绑定,每次执行cin操作前会自动刷新cout的缓冲区;

        解除绑定后,可以减少不必要的缓冲区刷新,提高输入效率。

3.  cout.tie(nullptr);

        解除cout与其他输出流的绑定(通常是cerrclog);

        进一步减少不必要的缓冲区同步操作,优化输出性能。

        需要注意的是,使用这些设置后,要避免混合使用 C++ 的cin/cout和 C 语言的scanf/printf,否则可能导致输出顺序错乱。

二、缺省参数

        缺省参数是声明或者定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则就需要使用指定的实参。缺省参数分为全缺省和半缺省参数。(有的地方把缺省参数又叫做默认参数)

        全缺省就是把全部形参给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值。

        带缺省参数的函数调用时,C++规定必须从左到右依次给实参,不能跳跃给实参。

        函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值。

        传参:

#include <iostream>
#include <assert.h>
using namespace std;void Func(int a = 0)
{cout << a << endl;
} int main()
{Func(); // 没有传参时,使⽤参数的默认值Func(10); // 传参时,使⽤指定的实参return 0;
}

        全缺省与半缺省:

#include <iostream>
using namespace std;// 全缺省
void Func1(int a = 10, int b = 20, int c = 30)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl << endl;
} // 半缺省
void Func2(int a, int b = 10, int c = 20)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl << endl;
} int main()
{Func1();Func1(1);Func1(1,2);Func1(1,2,3);Func2(100);Func2(100, 200);Func2(100, 200, 300);return 0;
}

三、函数重载

        C++支持在同一作用域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同。这样C++函数调用就表现出了多态行为,使用更加灵活。C语言是不支持同一作用域中出现同名函数的。相关代码示例如下:

#include<iostream>
using 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;
}
// 返回值不同不能作为重载条件,因为调⽤时也⽆法区分
//void fxx()
//{}
//
//int fxx()
//{
// return 0;
//}// 下⾯两个函数构成重载
// f()但是调⽤时,会报错,存在歧义,编译器不知道调⽤谁
void f1()
{cout << "f()" << endl;
} void f1(int a = 10)
{cout << "f(int a)" << en
} int main()
{Add(10, 20);Add(10.1, 20.2);f();f(10);f(10, 'a');f('a', 10);return 0;
}

四、引用

4.1  引用的概念和定义

        引用不是新定义一个变量,而是给已经存在的变量取一个别名。编译器不会为引用变量开辟内存空间,它和它引用的变量是共用同一块内存空间的。比如:水浒传中的李逵,宋江叫"铁⽜",江湖上⼈称"⿊旋⻛";林冲,外号豹⼦头等等。

        引用的格式如下:

类型&  引⽤别名 = 引⽤对象; 

        在C++中为了避免引入太多的运算符,会复用一些C语言的符号,比如前面的 << 和 >>,在这里引用也和取地址使用了同一个符号&,大家在使用时根据使用方法的角度来进行区分就好了。

        代码示例如下所示:

#include<iostream>
using namespace std;int main()
{int a = 0;// 引⽤:b和c是a的别名int& b = a;int& c = a;// 也可以给别名b取别名,d相当于还是a的别名int& d = b;++d;// 这⾥取地址我们看到是⼀样的cout << &a << endl;cout << &b << endl;cout << &c << endl;cout << &d << endl;return 0;
}

4.2  引用的特性

        (1)引用在定义时必须初始化;

        (2)一个变量可以有多个引用;

        (3)引用一旦引用了一个实体,就再也不能引用其他实体了。

        我们依旧根据代码示例来加深一下对于引用特性的理解:

#include<iostream>
using namespace std;int main()
{int a = 10;// 编译报错:“ra”: 必须初始化引⽤//int& ra;int& b = a;int c = 20;// 这⾥并⾮让b引⽤c,因为C++引⽤不能改变指向,// 这⾥是⼀个赋值b = c;cout << &a << endl;cout << &b << endl;cout << &c << endl;return 0;
}

4.3  引用的使用

        引用在实践中主要是于引用传参和引用做返回值中,减少拷贝提高效率和改变引用对象时,同时改变被引用对象的。

void Swap(int& rx, int& ry)
{int tmp = rx;rx = ry;ry = tmp;
} int main()
{int x = 0, y = 1;cout << x <<" " << y << endl;Swap(x, y);cout << x << " " << y << endl;return 0;
}

        引用传参跟指针传参的功能是类似的,但引用传参相对来说会更方便一些。

        引用返回值的场景相对来说是比较复杂的,博主在这简单讲一下场景,还有一些内容会在后续的类和对象博客中进行深入的讲解。

        引用和指针在实践中是相辅相成的,功能上具有重叠性,但是各有特点,并且是相互不可替代的。C++的引用与其他语言的引用(如Java)是有很大的区别的。除了用法以外,最大的点在于,C++引用定义之后是不能改变指向的,但Java的引用可以改变指向。

        一些主要用C语言代码实现的版本的数据结构教材中,常常使用C++引用替代指针传参,目的在于简化程序,并避开复杂的指针。如下代码所示:

// ⼀些主要⽤C代码实现版本数据结构教材中,使⽤C++引⽤替代指针传参,⽬的是简化程序,避开复
//杂的指针,但是很多同学没学过引⽤,导致⼀头雾⽔。
void SeqPushBack(SLT& sl, int x)
{}typedef struct ListNode
{int val;struct ListNode* next;
}LTNode, *PNode;

        对于指针变量而言,其实也是可以取别名的,在下面的代码中,LTNode*& phead 就是给指针变量取别名,这样就不需要使用二级指针了,相对而言就简化了程序。

void ListPushBack(PNode& phead, int x)
{PNode newnode = (PNode)malloc(sizeof(LTNode));newnode->val = x;newnode->next = NULL;if (phead == NULL){phead = newnode;} else{//...    }
}

4.4  const引用

        我们可以引用一个const对象,但是必须使用const引用。const引用也可以用来引用普通对象,因为对象的访问权限在引用过程中是可以缩小的,但是不能放大。

        不过需要注意的是,类似   int& rb = a*3; double d = 12.34; int& rd = d; 这样的一些场景下,a*3的和结果保存在一个临时对象中,int& rd = d 也是类似的,在类型转换中会产生临时对象来存储中间值,也就是说,rb 和 rd 引用的都是临时对象,而C++规定临时对象具有常性,所以这里就触发了权限放大,必须要使用常引用才可以。

        所谓的临时对象,就是编译器需要一个空间来暂存表达式的求值结果时临时创建的一个未命名的对象,C++中把这个未命名的对象叫做临时对象。

        下面依旧给出一些代码示例:

int main()
{const int a = 10;// 编译报错:error C2440: “初始化”: ⽆法从“const int”转换为“int &”// 这⾥的引⽤是对a访问权限的放⼤//int& ra = a;// 这样才可以const int& ra = a;// 编译报错:error C3892: “ra”: 不能给常量赋值//ra++;// 这⾥的引⽤是对b访问权限的缩⼩int b = 20;const int& rb = b;// 编译报错:error C3892: “rb”: 不能给常量赋值//rb++;int c = 10;const int& rc = 30;// 编译报错: “初始化”: ⽆法从“int”转换为“int &”// int& rd = c * 3;const int& rd = c * 3;double e = 12.34;// 编译报错:“初始化”: ⽆法从“double”转换为“int &”// int& re = e;const int& re = e;return 0;
}

4.5  指针和引用的关系

        C++中指针和引用就像是两个性格迥异的亲兄弟,指针是哥哥,引用是弟弟,在实践中他们是相辅相成的,功能上具有重叠性,但是各自有自己的特点,互相是不可替代的。

        关于指针和引用的关系,有以下几点需要注意的地方:

(1)语法概念上,引用是一个变量的取别名,是不开空间的,指针是用于存储一个变量地址的,需要开空间

(2)引用在定义时必须进行初始化,指针建议初始化,但是在语法上不是必须的

(3)引用在初始化时引用一个对象之后,就不能再引用其他的对象;而指针可以不断地改变指向的对象

(4)引用可以直接访问指向对象,指针则需要解引用之后才能访问指向对象。

(5)对于sizeof函数,他们俩的含义是不同的。引用结果为引用类型的大小,但指针始终是地址空间所占的字节个数(在32为平台下为4个字节,64位下为8byte)。

(6)指针很容易出现空指针和野指针的问题,引用却很少出现这类问题,使用起来会更加安全

五、inline

        用inline修饰的函数叫做内联函数,在编译时C++编译器会在调用的地方展开内联函数,这样调用内联函数就需要建立栈帧了,就可以提高效率。

        inline对于编译器而言只是一个建议,也就是说,你加了inline编译器也可以选择在调用的地方不展开,不同编译器关于inline什么情况展开是各不相同的,因为C++标准没有规定这个。inline适用于频繁调用的短小函数,对于递归函数和代码相对多一些的函数,加上inline也会被编译器忽略。

        C语言实现宏函数时也会在预处理时替换展开,但是宏函数实现是很复杂很容易出错的,且不方便调试。C++为此设计了inline来替代C的宏函数。

        VS编译器在debug版本下默认是不展开inline的,这样会比较便于调试,debug版本想要展开的话需要设置一下以下两个地方:

        inline不建议函数的声明和定义分离到两个文件,如果分离的话就会导致链接错误。因为inline被展开的话,就没有函数地址,链接时就会出现报错。所以要把inline函数直接定义到.h文件中。

        我们尝试一下定义一个内联函数:

// F.h
#include <iostream>
using namespace std;inline void f(int i);// F.cpp
#include "F.h"
void f(int i)
{cout << i << endl;
} // main.cpp
#include "F.h"
int main()
{// 链接错误:⽆法解析的外部符号 "void __cdecl f(int)" (?f@@YAXH@Z)f(10);return 0;
}

        出现上述报错的原因就是未在头文件中定义inline函数,加上定义后即可消除报错。

六、nullptr

        在C语言中我们学习过了NULL,实际上NULL是一个宏,在传统的C头文件(stddef.h)中,我们可以看到如下的定义:

#ifndef NULL#ifdef __cplusplus#define NULL     0#else#define NULL     ((void *)0)#endif
#endif

        在C++中NULL可能会被定义为字面常量0,或者C中被定义为无类型指针(void*)的常量。不论采取的是何种定义,在使用空值的指针时,都会不可避免地遇到一些麻烦,本想通过 f(NULL) 调用指针版本的 f(int*) 函数,但是由于NULL被定义成了0,于是就会调用 f(int x) ,因此与程序的初衷相悖。f((void*)NULL); 的调用会产生报错。如下代码所示:

#include<iostream>
using namespace std;void f(int x)
{cout << "f(int x)" << endl;
} void f(int* ptr)
{cout << "f(int* ptr)" << endl;
} int main()
{f(0);// 本想通过f(NULL)调⽤指针版本的f(int*)函数,但是由于NULL被定义成0,调⽤了f(intx),因此与程序的初衷相悖。f(NULL);f((int*)NULL);// 编译报错:error C2665: “f”: 2 个重载中没有⼀个可以转换所有参数类型// f((void*)NULL);f(nullptr);return 0;
}

        于是在C++11中就引入了nullptr,nullptr是一个特殊的关键字,也是一种特殊类型的字面量。它可以转换成其他任意类型的指针类型。使用nullptr定义空指针就可以避免类型转换的问题。因为nullptr只能够被隐式地转换为指针类型,而不能被转换为整数类型。


总结

        本期博客我为大家介绍了C++的输入输出、缺省、重载、引用等不同方面的基础知识,相信一定能为大家接下来的学习打好基础。下期博客我们将开始类和对象的学习,希望大家多多关注哦!

http://www.dtcms.com/a/396357.html

相关文章:

  • Pyside6 + QML - 信号与槽07 - 一个函数被多个信号触发
  • 网站建设经费的请示中国建设门户网登录入口
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(35):文法運用10课2+文法と使いえ方3)
  • 通过新闻学习日语,标题《ビール各社 厳しい暑さでも育つホップの栽培技術開発など進む》
  • 中国建设银行章丘支行网站做网站排名有用吗
  • 《模拟电子技术》之结型场效应管
  • 【Jenkins】配置到实战教程
  • 国之珍微站个人网站wordpress渗透
  • 有那些网站可以做推广企业网站建设 厦门
  • 站群系统源码微信外卖小程序加盟
  • 重庆直播网站平台建设小程序制作样式
  • 免费注册域名FreeDomain
  • Linux C语言基于FP寄存器进行栈回溯
  • 网站项目团队介绍怎么写网站建设需要哪些的ps
  • 网站做好了怎么办用rp怎么做网站功能按钮
  • 水果购物网站|基于java+vue的水果购物网站系统(源码+数据库+文档)
  • 巩义移动网站建设如何制作个人网页缴费
  • 深圳做企业网站1个亿用户的服务器多少钱
  • 电子商务有限公司网站济宁鱼台网站建设
  • 从“万能 ES”到专业 ClickHouse:一次埋点数据存储的选择
  • ICCV-2025 | 斯坦福人形机器人自主导航!LookOut:真实环境人形机器人第一人称视角导航
  • 网络销售网站数据库设计工具
  • stm32定时器:什么是 Timer Trigger Output Event
  • 网站推广有哪些方式如何用群晖做自己的网站
  • 网站后台管理员职责页游做的好的是哪个网站
  • 汕头网站设计浩森宇特自己做游戏app的网站
  • 做火锅加盟哪个网站好域名网安备案
  • seo网站推广与优化方案成交功能网站
  • 动漫网站模板建网站 温州
  • 北京网站建设 seo公司哪家好营口东站营销网站建设