【C++】初识C++基础篇·一(命名空间,函数重载,缺省参数,引用);

news2024/12/29 21:54:13

文章目录

  • 前言
  • 1.输入与输出
    • 输出
    • 输入
      • cin和scanf的对比
  • 2.命名空间
  • 2.1namespace存在的意义
  • 2.2namespace的使用
  • 3.缺省参数
  • 4.函数重载
    • 重载函数的调用规则
  • 5.引用

在这里插入图片描述

前言

我们先通过一段简单的代码来拉开C++的序幕;

//text.cpp
#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
	printf("hello world");
	return 0;
}


//int main()
//{
//	cout << "hello world" << endl;
//	return 0;
//}

在上述代码中,**printf(“hello world”);所实现的效果。与下面的cout << “hello world” << endl;**的效果相同,我们要知道在C++当中他是兼容C语言的语法的,所以代码中C语言的语法也能运行成功;
而在这里面就涉及到了我们下面要说的在C++中的输入与输出;

1.输入与输出

• < iostream > 是 Input Output Stream 的缩写,是标准的输⼊、输出流库,定义了标准的输⼊、输
出对象。
• std::cin 是 istream 类的对象,它主要⾯向窄字符(narrow characters (of type char))的标准输
⼊流。
• std::cout 是 ostream 类的对象,它主要⾯向窄字符的标准输出流。
• std::endl 是⼀个函数,流插⼊输出时,相当于插⼊⼀个换⾏字符加刷新缓冲区。
<<是流插⼊运算符,>>是流提取运算符。(C语⾔还⽤这两个运算符做位运算左移/右移)
• 使⽤C++输⼊输出更⽅便,不需要像printf/scanf输⼊输出时那样,需要⼿动指定格式, C++的输⼊输出可以⾃动识别变量类型其实最重要的是C++的流能更好的⽀持⾃定义类型对象的输⼊输出。
cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间中,所以要通过命名空间的使⽤⽅式去⽤他们
• ⼀般⽇常练习中我们可以using namespace std,实际项⽬开发中不建议using namespace std。
• 这⾥我们没有包含<stdio.h>,也可以使⽤printf和scanf, 因为在 < iostream >中间接包含了。vs系列编译器是这样的,其他编译器可能会报错。

对于输入和输出两种操作来说,最重要的就是流插入运算符和流提取运算符;

输出

输出:cout << “hello world” << endl;
"<<"符号表示的是将该字符串传给cout(传的只是地址),该符号指出了信息流动的方向;而且它不单单可以只传输一段字符串,甚至是多段、不同类型的多次拼接传输。例如:

#include<iostream>
#include<stdio.h>
using namespace std;
//int main()
//{
//	printf("hello world");
//	return 0;
//}


int main()
{
	cout << "hello world" << "  " << "123" << endl;
	return 0;
}

在这里插入图片描述
从结果中就可以验证我们上面所说的话;
而且在这里如果熟悉C语言的我们可以看出来流插入运算符,与我们C语言中的按位左移运算符相同,由于C++兼容C语言,区分就成了问题,所以就有了我们下面要讲的运算符重载

通过重载,同一个运算符将有不同的含义。编译器通过上下文来确定运算符的含义。C本身也有一些运算符重载的情况。例如,&符号既表示地址运算符,又表示按位AND运算符;*既表示乘法,又表示对指针解除引用。这里重要的不是这些运算符的具体功能,而是同一个符号可以有多种含义,而编译器可以根据上下文来确定其含义。C++扩展了运算符重载的概念,允许为用户定义的类型(类)重新定义运算符的含义。

输入

2.输入:cin >> a;

#include <iostream>

int main() {
  int num;
  std::cout << "Enter an integer: ";
  std::cin >> num;
  std::cout << "The number you entered is " << num << std::endl;
  return 0;
}

这个示例中,我们使用 std::cin 来从键盘读取一个整数,并将该整数存储在变量 num 中。我们还使用 std::cout 向用户输出提示信息和最终的整数值。
cin 可以读取各种类型的输入值,包括整数、浮点数、字符和字符串。

cin和scanf的对比

cin 支持所有 C++ 内置类型的数据输入,包括 int, float, double 等。 它还支持用户定义的数据类型,例如类和结构。另一方面,scanf 函数只支持 C 语言的基本类型,如 int, char, float, double 等。它不支持 C++ 类和结构体。
错误处理:
cin 使用构造函数抛出异常来处理输入错误。当您尝试读取不合适的类型或不是具有所需范围的类型的值时,会抛出一个异常。这使得可以在程序的其他部分捕获该异常,并对用户做出适当的反应。另一方面,scanf 使用返回值来指示输入的成功与否,并且没有异常。
性能:

1.cin 的性能可能比 scanf 高,因为前者通常使用循环和条件语句来处理输入,而后者通过从输入流中查找特定的字符进行输入。因此,使用 cin 可以更高效地读取大量的输入数据。
可读性和便携性:
2.cin 的语法和功能比 scanf 更易于理解和编写。 cin 使用各种工具,例如流插入和流提取符,使读取和写入数据的操作更直观。此外,cin 在 C++ 标准中定义,因此可在所有的 C++ 编译器中使用。

2.命名空间

2.1namespace存在的意义

在C/C++中,变量、函数和后⾯要学到的类都是⼤量存在的,这些变量、函数和类的名称将都存在于全局作⽤域中,可能会导致很多冲突。
使⽤命名空间的⽬的是对标识符的名称进⾏本地化,以避免命名冲突或名字污染,
namespace关键字的出现就是针对这种问题的。

namespace(命名空间)是一种用于组织代码中命名的机制。它提供了一种方法来避免命名冲突,并允许您创建多个具有相同名称的独立实体。
定义命名空间
可以使用以下语法来定义命名空间并指定其名称:

//text.cpp
namespace my_namespace {
  // 在这里定义命名空间的成员
}

我们通过一个C语言中错误的代码来理解:

#include <stdlib.h>
int rand = 10;
int main()
{
	// 编译报错:error C2365: “rand”: 重定义;以前的定义是“函数”
	printf("%d\n", rand);
	return 0;
}

而在C++中我们可以通过在命名空间中定义它来更好的解决;

2.2namespace的使用

• 定义命名空间,需要使⽤到namespace关键字,后⾯跟命名空间的名字,然后接⼀对{}即可,{}中
即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
• namespace本质是定义出⼀个域,这个域跟全局域各⾃独⽴,不同的域可以定义同名变量,所以下
⾯的rand不在冲突了。
• C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/
类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。局部域和全局域除了会影响
编译查找逻辑,还会影响变量的⽣命周期,命名空间域和类域不影响变量⽣命周期。

  1. namespace只能定义在全局,当然他还可以嵌套定义。

2.项⽬⼯程中多⽂件中定义的同名namespace会认为是⼀个namespace,不会冲突。
3.C++标准库都放在⼀个叫std(standard)的命名空间中。

在使用命名空间的成员时,我们需要使用名称空间的名称将其导入到当前范围。

#include<iostream>
using namespace std;
namespace study
{
	//变量
	int arr = 1;
	//函数
	int ADD(int left, int right)
	{
		return left + right;
	}
	//结构体
	struct Node
	{
		struct Node* next;
		int val;
	};
}

int main()
{
	cout << study::ADD(1, 2) << endl;
	return 0;
}

编译查找⼀个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间⾥⾯去查找。所以
下⾯程序会编译报错。所以我们要使⽤命名空间中定义的变量/函数,有三种⽅式:

• 1.指定命名空间访问,项⽬中推荐这种⽅式。
• 2.using将命名空间中某个成员展开,项⽬中经常访问的不存在冲突的成员推荐这种⽅式。
• 3.展开命名空间中全部成员,项⽬不推荐,冲突⻛险很⼤,⽇常⼩练习程序为了⽅便推荐使⽤。

// 指定命名空间访问
int main()
{
	printf("%d\n", N::a);
	return 0;
}

// using将命名空间中某个成员展开
using N::b;
int main()
{
	printf("%d\n", N::a);
	printf("%d\n", b);
	return 0;
}

//展开整个命名空间中的全部成员;
#include <iostream>

namespace my_namespace {
    void some_function() {
        std::cout << "Hello from my_namespace!" << std::endl;
    }
}
using namespace my_namespace;
int main() {
    some_function();
    return 0;
}

这里还有一个问题,当我们有两个命名空间,它们都定义了一个名为 sayHello 的函数。

// 在命名空间 `test` 中定义 `sayHello` 函数
namespace test {
  void sayHello() {
    std::cout << "Hello from test!" << std::endl;
  }
}

// 在命名空间 `test2` 中定义 `sayHello` 函数
namespace test2 {
  void sayHello() {
    std::cout << "Hello from test2!" << std::endl;
  }
}

int main() {
  using namespace test;
  using namespace test2;
  sayHello();
  return 0;
}

在这个示例中,我们使用 using 语句导入了 test 命名空间中的 sayHello 函数和 test2 命名空间中的 sayHello 函数。当我们调用 sayHello 函数时,C++ 编译器并不知道是调用 test::sayHello 还是 test2::sayHello。 在运行期间与两个函数冲突。
为了避免这种情况,您可以在每个命名空间中导入只自己需要的成员,或者在使用命名空间成员时显式引用命名空间,以确保编译器知道调用哪个函数。例如,
在这里插入图片描述
这时的解决方法就是显式引用了每个命名空间中的 sayHello 函数,以确保编译器知道我们正在调用哪个函数:

#include <iostream>

namespace test {
  void sayHello() {
    std::cout << "Hello from test!" << std::endl;
  }
}

namespace test2 {
  void sayHello() {
    std::cout << "Hello from test2!" << std::endl;
  }
}

int main() {
  test::sayHello();
  test2::sayHello();
  return 0;
}

3.缺省参数

• 缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。在调⽤该函数时,如果没有指定实参
则采⽤该形参的缺省值,否则使⽤指定的实参,缺省参数分为全缺省和半缺省参数。(有些地⽅把
缺省参数也叫默认参数)
• 全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。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;
}

在这里插入图片描述

4.函数重载

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)" << endl;
}
int main()
{
	Add(10, 20);
	Add(10.1, 20.2);
	f();
	f(10);
	f(10, 'a');
	f('a', 10);
	return 0;
}

在这里插入图片描述

重载函数的调用规则

1.参数数量(或参数的顺序)应与函数定义匹配。
2.参数类型应与函数定义中参数类型匹配(考虑到 C++ 的类型转换基本原则)。如果函数定义中提供有默认的参数值,则重载函数调用时可以省略该描述符所引用的参数。

#include <iostream>

// 无参数的原型
void sideFunction() {
	std::cout << "Call with no parameters" << std::endl;
}

// 双参数原型,整型和双精度型参数
void sideFunction(int num, double num2) {
	std::cout << "Call with int and double arguments: " << num << " " << num2 << std::endl;
}

int main() {
	sideFunction();           // 调用无参数版本的 sideFunction()
	sideFunction(10, 3.14);   // 调用 int 和 double 参数版本的 sideFunction()
	return 0;
}

5.引用

引⽤不是新定义⼀个变量,⽽是给已存在变量取了⼀个别名,编译器不会为引⽤变量开辟内存空间,
它和它引⽤的变量共⽤同⼀块内存空间。
形式表现为:类型& 引用别名 = 引用对象;
并且它可以有多个引用别名;

int& a = b;
int& c = a;
此时a是b的引用别名;(**不要把引用符号“&”和取地址符号混淆**)
对别名a取别名c,c相当于还是a的别名;

它是与变量相关联的指针,但与其他指针不同,引用必须初始化指向某个已存在的对象,并且在整个其生命周期中都必须指向那个对象。引用就像指针一样,但是它们的一些优点是:

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;
}

这里面的b = c并非改变了引用指向,而是赋值,因为如果是改变了引用指向,根据我们上面给出的定理,引用别名和变量共用一块地址,所以我们只需要看它们的地址是否相同就能够判断出;
在这里插入图片描述
从地址中我们可以看出b 和 c 的地址并不相同,所以b = c只是赋值;

而下面这段代码中的形式,才是改变了引用指向;

#include <iostream>
using namespace std;
 
int main() {
	int a = 99, b = 32;
	int &r = a;
    a = 67;
	cout << a << ", " << r << endl; //67,67
 
    &r=b;//不能重新引用其他数据
    b = 88;
	cout << b << ", " << r << endl;
 
	return 0;
}

结果会报错为表达式必须为可修改的左值;在这里插入图片描述
最后对于引用中另外的关键知识点和问题,后面我会再写一篇文章专门讲解
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1951264.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++知识点总结:3.C++引用(自用)

C引用 1. 引用定义2. 引用的本质3. 引用和指针的不同之处补充指针常量和常量指针 4. 引用不能指代临时变量5. const引用&#xff08;常引用&#xff09;可以绑定临时数据6. const引用与转换类型 引用&#xff1a; [1]C语言中文网 [2]偶尔e网事,【C基础之二】常量指针和指针常量…

学习记录:ESP32控制舵机 FREERTOS BLE

控制舵机 PWM信号 PWM信号是一种周期性变化的方波信号&#xff0c;它有两个关键参数&#xff1a; 周期&#xff08;Period&#xff09;&#xff1a;一个完整的PWM信号的时间长度&#xff0c;通常用秒&#xff08;s&#xff09;或毫秒&#xff08;ms&#xff09;表示。占空比…

MQ消息队列+Lua 脚本实现异步处理下单流程

具体实现和代码可参考我以前做过的笔记&#xff1a;《黑马点评》异步秒杀优化|消息队列 回顾一下下单流程&#xff1a; 用户发起请求 会先请求Nginx,Nginx反向代理到Tomcat&#xff0c;而Tomcat中的程序&#xff0c;会进行串行工作&#xff0c; 分为以下几个操作&#xff1…

昇思25天学习打卡营第25天|基于 MindSpore 实现 BERT 对话情绪识别

基于 MindSpore 实现 BERT 对话情绪识别 模型概述 BERT&#xff08;双向编码器表征量&#xff09;是Google于2018年发布的一种先进语言模型&#xff0c;基于Transformer架构&#xff0c;具备双向上下文理解功能。BERT的预训练方法创新性地结合了两种任务&#xff1a; Masked …

高级网页爬虫开发:Scrapy和BeautifulSoup的深度整合

引言 在互联网时代&#xff0c;数据的价值日益凸显。网页爬虫作为一种自动化获取网页内容的工具&#xff0c;广泛应用于数据挖掘、市场分析、内容聚合等领域。Scrapy是一个强大的网页爬虫框架&#xff0c;而BeautifulSoup则是一个灵活的HTML和XML文档解析库。本文将探讨如何将…

凸优化笔记-基本概念

原文 文章目录 最小二乘问题 仿射affine hullaffine dimension 凸集锥集超平面和半空间单纯形整半定锥保凸性的操作透视函数 凸函数的条件1阶判定条件2阶判定条件 Epigraph 外图 m i n i m i z e f 0 ( x ) minimize\ \ \ f_0(x) minimize f0​(x) s u b j e c t t o f i ( …

Python 爬虫入门(一):从零开始学爬虫 「详细介绍」

Python 爬虫入门&#xff08;一&#xff09;&#xff1a;从零开始学爬虫 「详细介绍」 前言1.爬虫概念1.1 什么是爬虫&#xff1f;1.2 爬虫的工作原理 2. HTTP 简述2.1 什么是 HTTP&#xff1f;2.2 HTTP 请求2.3 HTTP 响应2.4 常见的 HTTP 方法 3. 网页的组成3.1 HTML3.1.1 HTM…

Debug下载与安装(Windows11)

前言 在安装配置前我们先下载一下我们需要用的文件 下载debug 百度网盘下载 下载DOSBox DOSBox 两个文件下载好后我们就开始安装和配置了 第一步&#xff1a;安装DOSBox 第二步&#xff1a;安装好后找到安装路径找到Options.bat文件并打开 第三步&#xff1a;在文件最下…

图片变色,背景方向渐变web

<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>图片变色</title> <script src"03.JS\3.8JS案例加强\JQuery.js"></script> <style> .image-filter…

nvm 安装和遇到的问题

环境 win 11 安装 下载安装包 访问 https://github.com/coreybutler/nvm-windows/releases 选择需要的版本继续下载安装基本是可以下一步下一步的啦&#x1f92d; 安装 node 我这里需要16.x.x的node&#xff0c;执行以下命令 nvm install 16使用 node nvm use 16问题 …

苹果CMS V10萌芽采集插件Pro v10.7.3

苹果CMS V10萌芽采集插件Pro v10.7.3 插件下载:萌芽采集插件Pro v10.7.3.zip 使用说明: 将addons文件和static文件放到你苹果cms程序的根目录并覆盖&#xff0c; 在登录后台在应用-应用市场启用。http://你的域名/admin.php/admin/mycj/union.html

卷积的意义及其派生(一)

1.卷积的意义 1.1从LTI的角度看 卷积最开始其实是信号处理中用来描述线性移不变系统Linear time-invariant systems的。线性&#xff0c;表明可以叠加&#xff0c;信号可以拆分成脉冲的响应&#xff1b;时不变&#xff0c;指信号不随着时间的迁移改变&#xff0c;意味着能量守…

计算机网络(Wrong Question)

一、计算机网络体系结构 1.1 计算机网络概述 D 注&#xff1a;计算机的三大主要功能是数据通信、资源共享、分布式处理。&#xff08;负载均衡、提高可靠性&#xff09; 注&#xff1a;几段链路就是几段流水。 C 注&#xff1a;记住一个基本计算公式&#xff1a;若n个分组&a…

C语言程序设计(二)

四.找素数 素数&#xff1a;除了1和它本身不再有其他因数的自然数。换句话说&#xff1a;一个大于1的自然数 &#xff0c;如果只能被1和它本身整除&#xff0c;那就是素数&#xff08;质数&#xff09;。 在打印中遇到的问题就是&#xff0c;知道怎么写却总是运行不起来。主要…

苦学Opencv的第十一天:图像的形态学操作

Python OpenCV从入门到精通学习日记&#xff1a;图像的形态学操作 前言 图像形态学是图像处理中的一个重要分支&#xff0c;主要关注图像中物体的形状和结构。通过形态学操作&#xff0c;我们可以对图像进行有效的分析和处理&#xff0c;例如图像的腐蚀与膨胀、开运算与闭运算…

Java 并发编程:一文了解 Java 内存模型(处理器优化、指令重排序与内存屏障的深层解析)

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 022 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…

VIN解析汽车详情|阿里云实现调用API接口

介绍&#xff1a; 本次解析通过阿里云云市场的云服务来实现通过17位车架号来自动识别车型的详细信息&#xff0c;首先需要准备选择一家可以提供查询的商品。 https://market.aliyun.com/apimarket/detail/cmapi00065864#skuyuncode5986400001 步骤1: 选择商品 如图点击免费…

【微软蓝屏】微软Windows蓝屏问题汇总与应对解决策略

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

关键词查找【Knuth-Morris-Pratt (KMP) 算法】

一个视频让你彻底学懂KMP算法_哔哩哔哩_bilibili KMP算法的核心是利用匹配失败后的信息&#xff0c;尽量减少模式串与主串的匹配次数以达到快速匹配的目的。 第一步&#xff1a;计算模式串(子串)和next[j]数组 模式串 前2位字母的next[j]固定是0 和 1 后续字母的nex[j]&…

项目实战——外挂开发(30小时精通C++和外挂实战)

项目实战——外挂开发&#xff08;30小时精通C和外挂实战&#xff09; 外挂开发1-监控游戏外挂开发2-秒杀僵尸外挂开发3-阳光地址分析外挂开发4-模拟阳光外挂开发5-无限阳光 外挂开发1-监控游戏 外挂的本质 有两种方式 1&#xff0c;修改内存中的数据 2&#xff0c;更改内存中…