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

【C++】初识C++(1)

 

个人主页:@我要成为c嘎嘎大王

希望这篇小小文章可以让你有所收获!

目录

前言

一、C++的第一个程序 

二、命名空间

2.1 namespace 的价值

2.2 namespace 的定义

 2.2.1  正常的命名空间定义

 2.2.2 命名空间可以嵌套

2.2.3 匿名命名空间

 2.2.4 同名的namespace会合并

2.3 namespace 的使用

 2.3.1 指定命名空间访问

2.3.2 using将命名空间中某个成员展开

2.3.3 展开命名空间中全部成员

三、C++输⼊&输出

 四、缺省参数

4.1 全缺省

4.2 半缺省

 4.3 函数声明和定义分离

 五、函数重载


前言

C++是在C语言的基础上发展而来的一种面向对象编程语言,它在保留C语言强大功能的同时,引入了许多新的特性。比如面向对象编程(OOP):类, 封装, 继承, 多态四大件,引用(Reference),模板(Template),命名空间(Namespace),异常处理(Exception Handling),标准模板库(STL)。

C++在很多领域有着广泛的应用,比如游戏开发,操作系统开发,嵌入式系统开发, 数据库管理系统,图形图像处理和网络通信(QT),虚拟现实(VR)和增强现实(AR),航空航天与军工领域等。

一、C++的第一个程序 

C++兼容C语言绝大多数的语法,所以C语言实现的helloworld依旧可以运行,C++中需要把定义文件代码后缀改为.cpp,vs编译器看到是.cpp就会调用C++编译器编译,linux下要用g++编译,不再是gcc

当然C++有⼀套自己的输入输出,严格说C++版本的helloworld应该是这样写的。 

二、命名空间

2.1 namespace 的价值

在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使⽤命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。 c语言项目类似下面程序这样的命名冲突是普遍存在的问题,C++引入namespace就是为了更好的解决这样的问题。

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

2.2 namespace 的定义

 2.2.1  正常的命名空间定义

  • 定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接⼀对{}即可,{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
  • namespace本质是定义出⼀个域,这个域跟全局域各自独立,不同的域可以定义同名变量,所以下面的rand不在冲突了。
  • C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。局部域和全局域除了会影响 编译查找逻辑,还会影响变量的生命周期,命名空间域和类域不影响变量生命周期。
#include <stdio.h>
#include <stdlib.h>
// niu是命名空间的名字,⼀般开发中是用项目名字做命名空间名。
namespace niu{// 命名空间中可以定义变量/函数/类型int rand = 10;int Add(int left, int right){return left + right;}struct Node{struct Node* next;int val;};
}
int main()
{
// 这⾥默认是访问的是全局的rand函数指针printf("%p\n", rand);
// 这⾥指定niu命名空间中的rand printf("%d\n", niu::rand);return 0;
}

 这里的::是作用域运算符,使用命名空间名称加作用域运算符就可以访问命名空间内的元素。

 2.2.2 命名空间可以嵌套

  • namespace只能定义在全局,当然他还可以嵌套定义。
#include <stdio.h>
#include <stdlib.h>
namespace niu
{//张三namespace zs{int rand = 1;int Add(int left, int right){return left + right;}}//李四namespace ls{int rand = 2;int Add(int left, int right){return (left + right) * 10;}}
}
int main()
{printf("%d\n", niu::zs::rand);printf("%d\n", niu::ls::rand);printf("%d\n", niu::zs::Add(1, 2));printf("%d\n", niu::ls::Add(1, 2));return 0;
}

2.2.3 匿名命名空间

  • 匿名命名空间:匿名命名空间是C++中的一种特殊命名空间,其主要特点是没有名称,且其中的变量和函数只能在声明它们的文件中访问。这种命名空间的使用在C++编程中非常有用,尤其是在处理全局变量和函数时,可以避免命名冲突,并将它们的作用范围限制在当前文件中,从而提高代码的可读性和可维护性。 
#include <stdio.h>
#include <stdlib.h>
namespace {int i = 10;int j = 20;
}int main() {printf("%d\n", i);printf("%d\n", j);return 0;
}

 2.2.4 同名的namespace会合并

  •  项目工程中多文件中定义的同名namespace会认为是⼀个namespace,不会冲突。
#include <stdio.h>
#include <stdlib.h>
namespace niu
{int i = 1;
}
namespace niu
{int j = 10;
}
int main() {printf("%d\n", niu::i);printf("%d\n", niu::j);
}

2.3 namespace 的使用

编译查找⼀个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间里面去查找。所以下面程序会编译报错。所以我们要使用命名空间中定义的变量/函数,有三种方式: • 指定命名空间访问,项目中推荐这种方式。

• using将命名空间中某个成员展开,项目中经常访问的不存在冲突的成员推荐这种方式。

• 展开命名空间中全部成员,项目不推荐,冲突风险很大,日常小练习程序为了方便推荐使用。

 2.3.1 指定命名空间访问

#include<stdio.h>
namespace niu
{int a = 0;int b = 1;
}
//int main()
//{
// 编译报错:error C2065 : “a”:未声明的标识符
//	printf("%d\n", a);
//	return 0;
//指定命名空间访问
//}
int main()
{printf("%d\n", niu::a);return 0;
}

2.3.2 using将命名空间中某个成员展开

#include<stdio.h>
namespace niu
{int a = 0;int b = 1;
}using niu::b;
int main()
{printf("%d\n", b);return 0;
}

2.3.3 展开命名空间中全部成员

#include<stdio.h>
namespace niu
{int a = 0;int b = 1;
}// 展开命名空间中全部成员using namespace niu;
int main()
{printf("%d\n", a);printf("%d\n", b);return 0;
}

展开命名空间中全部成员这种写法是很容易造成重定义的问题,比如在全局再定义一个变量a(a=10),会发生如下报错:

就近原则:如果在局部域定义一个变量a(a=10),则会优先输出在局部定义的变量 a 。 

小结:
在没有使用using声明或using指令展开命名空间的情况下,查找优先级为:函数局部域 > 全局域 > (未展开的)命名空间域。
如果使用了using声明或using指令来展开命名空间,则展开后的命名空间域中的名称将与全局域中的名称具有相同的查找优先级(但仅限于被展开的部分),但仍然低于函数局部域的优先级

三、C++输⼊&输出

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

  • std::cin 是istream类的对象,它主要面向窄字符的标准输入流。
  • std::cout是ostream类的对象,它主要面向窄字符的标准输出流。
  • std::endl是一个函数,流插入输出时,相当于插入一个换行字符加刷新缓冲区。
  • <<是流插入运算符,>>是流提取运算符。(C语言还用这两个运算符做位运算左移/右移)
  • 使用C++输入输出更方便,不需要像printf/scanf输⼊输出时那样,需要手动指定格式,C++的输入输出可以自动识别变量类型(本质是通过函数重载实现的,这个以后会讲到),其实最重要的是 C++的流能更好的支持自定义类型对象的输入输出。
  • IO流涉及类和对象,运算符重载、继承等很多面向对象的知识,这些知识我们还没有讲解,所以这里我们只能简单认识⼀下C++IO流的用法,后面我们会有专门的⼀个章节来细节IO流库。
  • cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间中,所以要通过命名空间的使用方式去用他们。
  • ⼀般日常练习中我们可以using namespace std,实际项目开发中不建议。
  • 这里我们没有包含<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;
}

 四、缺省参数

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

4.1 全缺省

#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;
}int main()
{Func1();Func1(1);Func1(1, 2);Func1(1, 2, 3);return 0;
}

4.2 半缺省

#include <iostream>
using namespace std;
// 半缺省
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()
{Func2(100);Func2(100, 200);Func2(100, 200, 300);return 0;
}

注意:C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值。 

 

 4.3 函数声明和定义分离

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

 

 五、函数重载

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

返回值不同不能作为重载条件,因为调用时也无法区分

 下面两个函数构成重载,但调用f1()时,会报错,存在歧义,编译器不知道调用谁

完 

希望这篇小小文章可以为你解答疑惑!
若上述文章有什么错误,欢迎各位大佬及时指出,我们共同进步!

http://www.lryc.cn/news/589287.html

相关文章:

  • UDP和TCP的主要区别是什么
  • ADC采集、缓存
  • Kafka——生产者消息分区机制原理剖析
  • Kafka亿级消息资源组流量掉零故障排查
  • Eplan API SQL
  • 记录一条sql面试题2
  • Kafka 4.0 技术深度解析
  • 4G模块 A7670G打电话并且播报TTS语音
  • 2025-7-15-C++ 学习 排序(4)
  • 项目进度与预算脱节,如何进行同步管理
  • Flex 布局精讲
  • labview生成exe应用程序常见问题
  • RocketMq 启动_源码分析
  • 程序“夯住“的常见原因
  • 高并发四种IO模型的底层原理
  • linux的磁盘满了清理办法
  • Java 大视界 -- Java 大数据机器学习模型在金融风险传染路径分析与防控策略制定中的应用(347)
  • gitee某个分支合并到gitlab目标分支
  • 3D数据:从数据采集到数据表示,再到数据应用
  • pc浏览器页面语音播报功能
  • 【C++】神奇的AVL树
  • Java项目:基于SSM框架实现的学生档案管理系统【ssm+B/S架构+源码+数据库+毕业论文+开题报告】
  • k8s之Attach 和 Mount
  • Oracle日期时间函数说明及与MySql区别说明
  • 设计模式一: 模板方法模式 (Template Method Pattern)
  • GeoTools 工厂设计模式
  • MySQL高级篇(二):深入理解数据库事务与MySQL锁机制
  • 智驾芯片软件分层测试
  • Spring 中 @Component和@Bean注解的区别
  • 背包问题(包括路径统计)