c++入门(命名空间, c++输入输出, 缺省参数)

news2024/11/18 7:51:13

文章目录

  • 1. 命名空间
    • 正确的命名定义
    • 命名空间的使用
  • 2. c++输入与输出
    • 标准输入输出对象
    • 向流写入 读取数据
  • 3. 缺省参数
    • 缺省参数分类
    • 缺省参数声明
    • 缺省参数初始值

c++的简单介绍

C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机, 20世纪80年代, 计算机界提出了OOP(object oriented programming:面向对象)思想,支持面向对象的程序设计语言应运而生。

1982年,Bjarne Stroustrup博士在C语言的基础上引入并扩充了面向对象的概念,发明了一种新的程序语言。为了表达该语言与C语言的渊源关系,命名为C++。因此:C++是基于C语言而产生的,它既可以进行C语言的过程化程序设计,可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计。

在这里插入图片描述

c++几乎兼容了98%的c语言的特性, 同时添加了面向对象,泛型以及c的不足弥补.
下面主要简单讲解c++对C语言的不足弥补的一些语法特性.

1. 命名空间

在C/C++中, 变量,函数和我们之后要学的类都是大量存在的, 这些变量,函数和类的名称都将存在全局作用域中, 可能会导致很多冲突.

使用命名空间的目的就是对标识符的名称进行本地化,以避免命名冲突或者名字污染, namespace关键字的出现就是针对这种问题的.

#include <stdio.h>
#include <stdlib.h>

int rand = 10;

int main()
{
    //c语言没法解决这样的命名冲突, namespace就是用来解决这个问题的
    printf("%d\n", rand);
    return 0;
}

在这里插入图片描述

编译器直接提示 rand 重定义了, 原来是一个函数, 在 <stdlib.h>库函数中.

C语言无法解决命名冲突, 比如我们定义的名称和库里的有冲突, 又比如团队中不同成员的互相之间有命名冲突.

如果在c语言遇到上面的问题, 是解决不了的, 解决方法只有改名.

而在c++, 提供了 namespace 关键字用来解决命名冲突


命名空间用关键字 namespace 定义, 后面跟着命名空间的名字, 然后跟着一对 {}, 在 {} 里面即命名空间的成员.

注意: {} 后面不需要跟着 ;

正确的命名定义

#include <stdio.h>
#include <stdlib.h>

// 正确的命名定义
namespace wr
{
    int rand = 10;
}

void fun()
{
    printf("%d\n", rand);
}

int main()
{
    fun();
    printf("%d\n", rand);
    return 0;
}

程序运行结果如下
在这里插入图片描述

我们发现, 程序并没有得到我们想要的结果.

编译器先从局部空间寻找有没有使用这个名字的变量, 如果局部空间没有, 那么就在全局空间来寻找. 全局空间找不到并不会在命名空间内寻找, 会直接报错

上述程序就是打印了库中 rand函数 的地址, 按整数打印.


一个命名空间就定义了一个新的作用域, 命名空间中的所有内容都限定在这个作用域内.

下面的程序可以更加直观的观察到, 在命名空间的成员不会被直接当成全局变量的.

#include <stdio.h>
#include <stdlib.h>

namespace wr
{
    int rand = 10;
    int x = 1;
}

int main()
{
    printf("%d\n", x);
    return 0;
}

在这里插入图片描述

编译器还没有编译就直接报错: x未定义

命名定义相当于一堵墙, 将变量围了起来, 我们使用它们需要指定的字符.


那么应该怎么样正确使用命名空间的成员呢?

一种方法就是用::域作用限定符, 来使用命名空间的成员.

比如我要使用名为wr命名空间的成员rand, 就需要这样 wr::rand(命名空间名 :: 命名空间成员)

#include <stdio.h>
#include <stdlib.h>

namespace wr
{
    int rand = 10;
    int x = 1;
}

void fun()
{
    int rand = 100;
    printf("%d\n", wr::rand);
}

int main()
{
    fun();
    printf("%d\n", wr::rand);
    printf("%d\n", wr::x);
    return 0;
}

在这里插入图片描述

这样就可以正确使用命名空间的成员了, 如果变量名前限定了命名空间, 会直接使用命名空间内的变量, 而不会再在局部空间和全局空间内找.


同样, 函数和结构体成员也是可以当作命名空间的成员的, 使用方式也是一样用域作用限定符

#include <stdio.h>
#include <stdlib.h>

namespace wr
{
    int rand = 10;
    
    int Add(int a, int b)
    {
        return a+b;
    }

    struct Node
    {
        int val;
        struct Node* next;
    };
}


int main()
{
    struct wr::Node n1 = {100, NULL};
    
    printf("%d\n", wr::Add(1, 2));
    printf("%d\n", n1.val);
    return 0;
}

程序运行结果如下:

在这里插入图片描述

注意域作用限定符是直接作用在名称上的, 例如struct wr::Node 而不是wr::struct Node


命名空间的好处就是防止发生命名冲突, 即使名称一样通过命名空间可以很好的解决这个冲突

#include <stdio.h>
#include <stdlib.h>

namespace wr
{
    int rand = 10;
    
    int Add(int a, int b)
    {
        return a+b;
    }
}

namespace wht
{
    int rand = 100;

    int Add(int a, int b)
    {
        return 10*(a+b);
    }
}

int main()
{
    printf("wr::Add(1, 2):%d\n", wr::Add(1, 2));
    printf("wr::rand:%d\n", wr::rand);

    printf("wht::Add(1, 2):%d\n", wht::Add(1, 2));
    printf("wht::rand:%d\n", wht::rand);
    return 0;
}

在这里插入图片描述


命名空间是可以嵌套的

#include <stdio.h>
#include <stdlib.h>

namespace N1
{
    int a = 10;
    int b = 11;

    int Add (int a, int b)
    {
        return a+b;
    }

    namespace N2
    {
        int c = 12;
        int d = 13;

        int Mul (int a, int b)
        {
            return a*b;
        }
    }
}

int main()
{
    printf("N1::a\t\t%d\n", N1::a);
    printf("N1::b\t\t%d\n", N1::b);
    printf("N1::N2::c\t%d\n", N1::N2::c);
    printf("N1::N2::d\t%d\n", N1::N2::d);
    printf("N1::Add(1,2)\t%d\n", N1::Add(1,2));
    printf("N1::N2::Mul(3,4)\t%d\n", N1::N2::Mul(3,4));

    return 0;
}

在这里插入图片描述


同一工程允许存在多个相同名称的命名空间, 编译器最后会合成一个命名空间
同一文件中的多个相同名称的命名空间, 也会合成一个命名空间

  • Stack.h
#include <stdio.h>
#include <stdlib.h>

namespace wr 
{
  typedef struct Stack
  {
    int* a;
    int capacity;
    int top;
  }ST;

  void StackInit(ST* ps);
  void StackPush(ST* ps, int x);
}
  • Stack.cpp
#include "Stack.h"

namespace wr 
{
  void StackInit(ST* ps)
  {
    ps->a = NULL;
    ps->capacity = ps->top = 0;
  }
  
  void StackPush(ST* ps, int x)
  {
    //...
  }
}
  • test.cpp
#include "Stack.h"
namespace wr 
{
  int x = 100;
}

int main()
{
  wr::ST s;
  wr::StackInit(&s);

  return 0;
}

程序运行没有任何问题, test.cpp 使用到了同工程其他文件的同名命名空间的成员.


命名空间的使用

还是使用上面栈的数据结构, 如果我想一次性将1,2,3,4,5压入栈, 需要如下操作

#include "Stack.h"
namespace wr 
{
  int x = 100;
}

int main()
{
  wr::ST s;
  wr::StackInit(&s);
  wr::StackPush(&s, 1);
  wr::StackPush(&s, 2);
  wr::StackPush(&s, 3);
  wr::StackPush(&s, 4);
  wr::StackPush(&s, 5);

  return 0;
}

在每个 StackPush 前面都要加上命名空间和域作用限定符, 这显然造成代码冗长.

有一种方法可以避免这种情况, 直接使用 using 指示, 将整个命名空间名称引入:

#include "Stack.h"
namespace wr 
{
  int x = 100;
}
using namespace wr;

int main()
{
  ST s;
  StackInit(&s);
  StackPush(&s, 1);
  StackPush(&s, 2);
  StackPush(&s, 3);
  StackPush(&s, 4);
  StackPush(&s, 5);

  return 0;
}

using指示使得某个特定的命名空间中所有的名字都可见, 这样我们就无需再为它们添加任何前缀限定符了.

简写的名字从 using 指示开始, 一直到 using 指示所在的作用域结束都能使用.


还有一种最安全的方法, 也就是使用 using 声明

#include <iostream>
using std::cin;

int main()
{
    int i;
    cin >> i;       //正确: cin和std::cin含义相同
    cout << i;      //错误: 没有对应的using声明, 必须使用完整的名字
    std::cout << i; //正确: 显示地从std中使用cout

    return 0;
}

在这里插入图片描述

这也是c++特有的输入输出代码, 马上就会讲解这个知识点, 首先中心放在 using 声明里.

第232行, 编译器直接提示我没有对应的using声明.

当然, 我是可以直接用 using 指示: using namespace std
但是, 库中的命名空间 std 显然有很多成员, 如果一次性全部展开, 这是不安全的, 最好最安全的方式就是使用 using 声明. 我需要用到什么成员, 我就声明什么成员.


综上:

命名空间的使用有三种方式:

  • 加命名空间名称及作用域限定符 ::
  • using 声明: 使用using将命名空间中某个成员引入
  • using 指示: 使用using namespace 命名空间名称 引入

注意: 头文件不应包含 using 声明. 如果头文件有某个 using 声明, 那么每个使用的该头文件的文件就都会有这个圣经. 对于某些程序来说, 由于不经意间包含了一些名字, 反而可能产生始料未及的名字冲突.


2. c++输入与输出

c++并未定义任何输入输出(IO)语句, 取而代之, 包含了一个全面的标准库(standard library) 来提供 IO机制(以及很多其他设施)

iostream 库包含两个基础类型 istreamostream, 分别表示输入流和输出流.

一个流就是一个字符序列, 随着时间的推移, 字符是顺序生成或消耗的.

标准输入输出对象

标准库定义了4个 IO 对象.

cin : 标准输入(键盘)
cout : 标准输出(控制台)
cerr : 标准错误
clog : 输出程序运行时的一般性信息

实际上 cincout 分别是 istreamostream 类型的对象, 后序会详细讲解

向流写入 读取数据

#include <iostream>
using std::cout;
using std::cin;
using std::endl;

int main()
{
    int n1, n2;

    cout << "请输入两个数字: " << endl;
    cin >> n1 >> n2;
    cout << n1 << 'x' << n2 << '=' << n1*n2 << endl;

    return 0;
}

在这里插入图片描述


向流写入数据

cout << "请输入两个数字: " << endl;

这句表达式使用了**输出运算符(<<)**在标准输出上打印信息.

<< 接受两个运算对象: 左侧的运算对象必须是一个 ostream 对象, 右侧的运算对象是要打印的值.

endl 是一个被称为 操纵符 的特殊值. 写入 endl 的效果是结束当前行, 相当于\n.


从流中读取数据
cin >> n1 >> n2;用于读入输入数据

输入运算符(>>) 与输出运算符类似, 它接受一个 istream 作为其左侧运算对象, 接受一个对象为其右侧运算对象.


使用c++输入输出更方便, 不需要像 printf/scanf 那样, 需要手动输入格式. c++的输入输入可以自动识别格式.

#include <iostream>

using namespace std;

int main()
{
    int a;
    double b;
    char c;

    cin >> a >> b >> c;
    cout << a << endl;
    cout << b << endl; 
    cout << c << endl;

    return 0;
}

在这里插入图片描述

若有打印精度的需求, 可以输入输出流和printf/scanf函数结合使用, 当然官方库也提供了一些方法, 如果需要用可以自查.

3. 缺省参数

缺省参数是在声明或定义函数时为函数参数指定一个缺省值.

在调用该函数时, 如果没有指定实参则使用该形参的缺省值, 否则则使用该实参.

void Func(int a = 0)
{
    cout<<a<<endl;
}

int main()
{
    Func();     // 没有传参时,使用参数的默认值
    Func(10);   // 传参时,使用指定的实参

    return 0;
}

程序运行如下:
在这里插入图片描述


缺省参数让函数调用非常灵活

缺省参数分类

  • 全缺省参数

函数的所有形参都提供了默认实参

void Func(int a = 1, int b = 2, int c = 3)
{
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;
    cout << endl;
}

int main()
{
    Func();
    Func(20);           // a = 20; 
    Func(20, 30);       // a = 20; b = 30;
    Func(20, 30, 40);   // a = 20; b = 30; c = 40;

    return 0;
}

在这里插入图片描述

若函数有多个形参有默认实参, 如果函数指定了实参, 默认从第一个有默认实参的形参开始指定实参.

只能省略尾部的实参, 而不能省略前面的实参.

例如下面的函数调用就是错误的

Func(, 20, );

  • 半缺省参数

至少有一个形参没有默认实参

void Func(int a, int b = 2, int c = 3)
{
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;
    cout << endl;
}

int main()
{
    Func();             // err
    Func(20);           // a = 20; 
    Func(20, 30);       // a = 20; b = 30;
    Func(20, 30, 40);   // a = 20; b = 30; c = 40;

    return 0;
}

根据我们上面得到的结论

拥有半缺省参数的函数, 对于没有默认实参的形参, 都需要在函数调用的时候指定实参.

半缺省参数必须从右向左依次来给出, 不能间隔着给

void Func(int a = 1, int b, int c);         //err
void Func(int a = 1, int b, int c = 3);     //err
void Func(int a, int b = 2, int c);         //err
void Func(int a, int b, int c = 3);         //正确  

总结: 缺省参数后面都应为缺省参数.

合理设置形参的顺序, 尽量让不怎么使用默认值的形参出现在前面, 而让哪些经常使用默认值的形参出现在后面.


缺省参数声明

对于函数的声明来说, 通常的习惯是将其放在头文件中, 并且一个函数只声明依次, 但是多次声明同一个函数也是合法的!

不过需要注意的是, 函数的后序声明只能为之前那些没有默认值的形参添加默认实参, 而且该形参的右侧的所有形参必须都有默认值.

例如已经声明了一个函数:

void Func(int a, int b, int c = 3);

是不可以在这个声明后面对已经有默认值的形参进行修改默认值的:

void Func(int a, int b, int c = 4);     //错误 在上面已经对 c 赋值过默认值, 不可再进行修改

同样,如果该形参的右边不全是缺省参数也是不可以的:

void Func(int a = 1, int b, int c = 3);   //错误 形参 a 右侧不全是缺省参数

下面这样是正确的

void Func(int a = 1, int b = 2, int c = 3);

通常来说, 应该在函数声明中指定缺省参数, 不可在函数声明和函数定义同时指定缺省参数


缺省参数初始值

缺省值必须是常量或全局变量.不可以是局部变量

int i = 10;
int j = 20;

void Func(int a = i; int b = j; int c = 3)
{
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;
    cout << endl;
}

int main()
{
    Func();         //a = 10; b = 20; c = 3;
    
    i = 100;        //改变了默认实参的值
    int j = 200;    //没有改变默认实参的值
    Func();         //a = 100; b = 20; c = 3;

    return 0;
}

在这里插入图片描述

如果缺省参数的缺省值是全局变量, 那么他们的缺省值是在函数调用后才真正开始计算.
这也就是为什么在修改了全部变量后, 形参的默认值也发生了改变.

本章完.

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

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

相关文章

全波形反演培训的思考与总结

一. InversionNet 最简单的端到端DL_FWI 1. 网络结构&#xff1a; 图1 构建了一个具有编码器-解码器结构的卷积神经网络&#xff0c;根据地震波动数据模拟地下速度结构。编码器主要由卷积层构建&#xff0c;它从输入地震数据中提取高级特征并将其压缩为单个高维向量。解码器然后…

轻量级导出 Excel 标准格式

一般业务系统中都有导出到 Excel 功能&#xff0c;其实质就是把数据库里面一条条记录转换到 Excel 文件上。Java 常用的第三方类库有 Apache POI 和阿里巴巴开源的 EasyExcel 等。另外也有通过 Web 模板技术渲染 Excel 文件导出&#xff0c;这实质是 MVC 模式的延伸&#xff0c…

系列四、FileReader和FileWriter

一、概述 FileReader 和 FileWriter 是字符流&#xff0c;按照字符来操作IO。 1.1、继承体系 二、FileReader常用方法 new FileReader(File/String)# 每次读取单个字符就返回&#xff0c;如果读取到文件末尾返回-1 read()# 批量读取多个字符到数组&#xff0c;返回读取的字节…

【C语言】每日一题(添加逗号)

添加逗号&#xff0c;链接奉上 目录 方法1&#xff1a;整体存入思路&#xff1a;代码实现&#xff1a; 方法2&#xff1a;分段输出思路&#xff1a;代码实现&#xff1a; 方法1&#xff1a;整体存入 思路&#xff1a; 整体思路&#xff1a; 我们发现这个整数N对于最后1位是比…

【Python生活脚本】视频转Gif动图

忘记过去&#xff0c;超越自己 ❤️ 博客主页 单片机菜鸟哥&#xff0c;一个野生非专业硬件IOT爱好者 ❤️❤️ 本篇创建记录 2023-10-20 ❤️❤️ 本篇更新记录 2023-10-20 ❤️&#x1f389; 欢迎关注 &#x1f50e;点赞 &#x1f44d;收藏 ⭐️留言&#x1f4dd;&#x1f64…

Juniper防火墙SSG-140 session 过高问题

1.SSG-140性能参数 2.问题截图 3.解决方法 &#xff08;1&#xff09;通过telnet 或 consol的方法登录到防火墙&#xff1b; &#xff08;2&#xff09;使用get session 查看总的session会话数&#xff0c;如果大于300 一般属于不正常情况 &#xff08;3&#xff09;使用get…

力扣每日一题48:旋转图像

题目描述&#xff1a; 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],…

任务分配问题(回溯法)

算法设计 问题描述 有n&#xff08;n≥1&#xff09;个任务需要分配给n个人执行&#xff0c;每个任务只能分配给一个人&#xff0c;每个人只能执行一个任务。 第i个人执行第j个任务的成本是c[i][j]&#xff08;1≤i&#xff0c;j≤n&#xff09;。求出总成本最小的分配方案 …

基于Java的人事管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

推荐《中华小当家》

《中华小当家&#xff01;》 [1] 是日本漫画家小川悦司创作的漫画。该作品于1995年至1999年在日本周刊少年Magazine上连载。作品亦改编为同名电视动画&#xff0c;并于1997年发行播出。 时隔20年推出续作《中华小当家&#xff01;极》&#xff0c;于2017年11月17日开始连载。…

简述两种爆破ssh弱口令的方法

SSH 为 Secure Shell 的缩写&#xff0c;由 IETF 的网络小组&#xff08;Network Working Group&#xff09;所制定&#xff1b;SSH 为建立在应用层基础上的安全协议。SSH 是目前较可靠&#xff0c;专为远程登录会话和其他网络服务提供安全性的协议。利用 SSH 协议可以有效防止…

【C语言必知必会| 第十篇】指针入门,这一篇就够了

引言 C语言是一门面向过程的、抽象化的通用程序设计语言&#xff0c;广泛应用于底层开发。它在编程语言中具有举足轻重的地位。 此文为【C语言必知必会】系列第十篇&#xff0c;介绍C语言指针&#xff0c;结合专题优质题目&#xff0c;带领读者从0开始&#xff0c;深度掌握知识…

(N-128)基于springboot,vue酒店管理系统

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 系统分前后台&#xff0c;项目采用前后端分离 前端技术&#xff1a;vueelementUI 服务端技术&#xff1a;springbootmybatis 本系统功…

推荐《机动战士高达SEED DESTINY》

《机动战士高达SEED DESTINY》是《机动战士高达SEED》的续集&#xff0c;于日本时间2004年10月9日—2005年10月1日每周六下午六点在每日放送、TBS电视台系列电视台播出&#xff0c;全50话。 [1] 台湾版权由博英社取得&#xff0c;并于2005年10月8日起由中国电视公司在每周六播…

光伏三相并网逆变器的控制策略与性能分析(Simulink仿真实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【c语言】atoi的模拟实现

1.头文件 atoi() 是 C语言的一个标准库函数&#xff0c;定义在<stdlib.h>头文件中 2.atoi的解析 具体来讲&#xff0c;atoi() 函数首先会丢弃尽可能多的空白字符&#xff0c;直至找到第一个非空白字符&#xff0c;然后从该字符开始&#xff0c;识别 “”、“-” 以及 …

Python---循环---while循环

Python中的循环 包括 while循环与for循环&#xff0c;本文以while循环为主。 Python中所有的知识点&#xff0c;都是为了解决某个问题诞生的&#xff0c;就好比中文的汉字&#xff0c;每个汉字都是为了解决某种意思表达而诞生的。 1、什么是循环 现实生活中&#xff0c;也有…

华硕ROG吹雪和微星刀锋钛两者如何选择

## 华硕Rog系列主板里面的吹雪和微星主板里面的刀锋钛两者相比分别有什么特点&#xff0c;二选一应该选择哪个&#xff1f; 首先&#xff0c;要明确"吹雪"和"刀锋钛"并不是主板本身的名称&#xff0c;而是主板系列或某种设计风格的称呼。华硕和微星都是非常…

隐式类型转换

什么是隐式类型转换&#xff0c;多参数的造函数隐式类型转换&#xff0c;和单参数的构造函数隐式类型转换有什么区别 C中有三种主要的隐式类型转换&#xff1a; 1:多参数的构造函数隐式类型转换 2:单参数的构造函数隐式类型转换 3:成员函数隐式类型转换。…

【KingHistorian】新授权配置与使用说明

哈喽&#xff0c;大家好&#xff0c;我是雷工。 今天在现场安装KingHistorian的授权时&#xff0c;一时想不起来上次咋安装的了&#xff0c;真是好记性不如烂笔头&#xff0c;更何况记性还不咋地&#xff0c;又琢磨了半小时才想起来&#xff0c;现将授权配置与使用说明整理如下…