C++入门,一些C++基本概念介绍

news2024/11/26 20:44:47

文章目录

目录

前言

1.C++关键字

1.1命名空间

1.2命名空间定义

1.3命名空间的使用

2.C++输入&输出

3.缺省参数

3.1缺省参数的概念

3.2缺省参数分类

4.函数重载

4.1函数重载的概念

5.引用

5.1 引用特性

5.2 常引用

5.3引用的使用场景

5.4引用和指针

6.内联函数

6.1内联的特性

7.宏

8.auto关键字(c++11)

8.1 auto的使用细则

9.基于范围的for循环(语法糖)

9.1范围for的语法

9.2范围for的使用条件

10.指针空值--nullptr(c++11)

总结

 


前言

什么是C++:

        C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,需要高度的抽象和建模时,C语言则不合适。C++是基于C语言产生的,它可以进行C语言的过程化程序设计,又可以以抽象数据类型为特点的,基于对象的程序设计,还可以进行面向对象的程序设计。


1.C++关键字

C++总计63个关键字,如下图所示,具体用法可参考后续文章。

1.1命名空间

        在c/c++中,变量,函数和后面需要学的类都是大量存在的,这些变量,函数和类的名称都存在于全局作用域中,会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或者名字污染,namesapce关键字就是针对这种问题的。

1.2命名空间定义

        定义命名空间,需要使用namespace关键字,后面跟命名空间的名字,接一对{}即可,{}中即为命名空间的成员

1、正常的命名空间定义

namespace Queue{
    //命名空间中可以定义变量/函数/类型
    int rand = 10;
    int Add(int left, int right)
    {
        return left+right;
    }
    struct Node
    {
        struct Node * next;
        int val;
    }
}



2、命名空间可以嵌套
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、同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成在同一个命名空间中
    //test.h 
    namespace N1
    {
        ...
    }
    //test.cpp
    namespace N1
    {
        ...
    }
    
test.h和test.cpp中的两个N1会被合并成一个

注意:一个命名空间就定义了一个新的作用域,命名空间中所有的内容都局限于该命名空间中。

1.3命名空间的使用

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

  1. 加命名空间名称以及作用域限定符
  2. 使用using将命名空间中的某个成员引入
  3. 使用using namespace 命名空间名称引入  
namespace byte
{
    int a = 0;
    int b = 1;
    int Add(int left,int right)
    {
          return left+right;
    }
    
    ...
}

int main()
{
    printf("%d" ,a);
}


1.加命名空间名称以及作用限定符
int main()
{
    printf("%d" ,byte::a);
}



2.使用using将命名空间某个成员引入
using byte::b;
int main()
{
    printf("%d" ,b);
}


3.使用using namespace 命名空间名称引入
using namespace N;
int main()
{
  
    printf("%d" ,a);
}


2.C++输入&输出

#include<iostream>
using namespace std;

int main()
{
    cout<<"hello world!"<<endl;
}

说明:

1.使用cout标准输出对象(控制台)和cin标准输入对象时,比如包含<iostream>头文件,以及按命名空间使用方法使用std;

2.<<是流插入运算符; >>是流提取运算符

3.cout和cin是全局的流对象,endl是特殊的c++符号,表示换行输出,都包含在iostream头文件中

4.使用c++输入和输出更方便,c语言中使用printf和scanf需要手动控制格式,c++可以直接自动识别变量类型

注意:早期标准库将所有功能在全局域下实现,声明在.h后缀的头文件中,使用时包含对应头文件即可,后来在std的命名空间下,和c头文件进行区分,规定c++头文件不带.h,推荐使用<iostream>+std的方式

#incllude<iostream>

using namespace std;

std命名空间的使用惯例:

std是c++标准库的命名空间

1.日常使用中,建议直接使用using namespcae std即可

2.using namespace std展开,标准库都暴露出来,自定义和库重名的类型/对象/函数就存在冲突问题,在开发项目中使用: std::cout; using std::cout展开常用的库对象/类型等方式

3.缺省参数

3.1缺省参数的概念

        缺省参数是声明或定义函数时为函数的参数指定一个缺省值,在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。

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

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

     return 0;
}

3.2缺省参数分类

  • 全缺省参数
void Func(int a = 10 ,int b = 20, int c = 30)
{
    count<<a<<endl;
    count<<b<<endl;
    count<<c<<endl;
}

  • 半缺省参数
void Func(int a, int b = 10,int c = 20)
{
    cout<<a<<endl;
    cout<<b<<endl;
    cout<<c<<endl;
}

注意:

1.半缺省参数必须从右往左依次给出,不能间隔给

int main()
{
    Fun(1);
    Func(1,2);
    Func(1,2,3);
    Fun(,20,)//err 
    //调用的时候赋值从左往右,缺省参数给的时候从右往左
}

2.缺省参数不能在定义和声明中同时出现

//如果声明和定义同时出现,两个位置提供的值不同,编译器无法确定使用哪个缺省值

4.函数重载

4.1函数重载的概念

       函数重载:是函数的一种特殊情况,c++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数或类型或类型顺序)不同,常用来处理实现功能类似,数据不同的问题

#include<iostream>
using namespcae stdl
//1.参数类型不同
int Add(int left,int right)
{
    return left+right;
}

double Add(double left,double right)
{
    return left+right;
}

//2.参数个数不同
void f()
{
    count<<"f()"<<endl;
}

void f(int a)
{
    cout<<"f(int a)"<<endl;
}

//3.参数类型顺序不同
void f(int a,char b)
{
    ...
}

void f(char b, int a)
{
    ...
}

支持重载的原理:

        在c/c++中,一个程序运行起来需要:预处理,编译,汇编,链接

        

1.实际项目通常是由多个头文件和源文件组成,当前a.cpp中调用了b.cpp中定义的add函数时,编译后,链接前,a.o中目标文件没有add的函数地址,因为add是在b.cpp中定义的,在链接阶段处理这个问题,链接器看到a.o中调用add,但是没有add的地址,就会到b.o的符号表中找到add的地址,然后链接在一起

2.在链接时,面对add函数,去找这个函数名字(通过g++修饰的规则),编译器将函数参数类型信息添加到修改后的名字中

3.C++就是通过函数修饰来区分,只要参数不同,修饰出来的名字就不同,构成了函数重载。

4.如果两个函数,函数名和参数相同,但是返回值不同,无法构成重载,因为编译器无法区分。

5.引用

        引用不是定义了一个新变量,而是给已存在的变量取别名,编译器不会为引用变量开辟新的内存空间,它和它引用的变量共用一块内存。

void Test()
{
    int a = 10;
    int& ra = a;
}

//引用类型必须和引用实体是同种类型的

5.1 引用特性

  • 引用在定义的时候必须初始化
  • 一个变量可以有多个引用
  • 引用一旦引用一个实体,再不能引用其他实体

5.2 常引用

void Test()
{
    const int a = 10;
    // int& ra = a ; err,a为常量
    const int & ra = a;

    //int& b  = 10 ; //err,b为常量
    const int& b = 10;
    

    double d = 13.15;
    //int & rd = d; //err 类型不同
    const int& rd = d;
}

5.3引用的使用场景

  • 作参数(输出型参数,形参的改变影响实参)

    C语言中,如果使用一般形参,形参是实参的临时拷贝,则定义了指针去改变。c++中传引用。

void swap(int& r1, int&ra)
{
    ...
}

int main()
{
    int a = 0, b = 1;
    swap(a,b);
}


//递归里面,如果直接传变量,这层调用完,形参改变,
//并不会改变上一层的参数,这时候也可以使用引用
  • 作为返回值
int &Count()
{
    static int n = 0;  //n存在静态区
    n++;
    //...
    return n;
}
int Count()
{
    static int n = 0;  
 //无static n是临时变量,定义在count栈里面,出了作用域返回,
 //n不能直接给ret 此时count已经调用完成,栈帧销毁。 此时n给一个临时变量,这个临时变量作为函数的返回值 如果比较小,通常使用寄存器充当
//有static n 存在静态区,栈销毁不会影响n,n也会给一个临时变量作为返回值(不会把n直接给ret)
    n++;
    
    return n;
 }

int main()
{
    int ret = Count()
    return 0;
}

上述代码也有优化的空间,可以使用引用去作为返回值,减少拷贝。

出了作用域,它的声明周期还在,就可以使用传引用返回。

//传引用返回,产生了一个n的别名
int& Count()
{
    static int n = 0;
    n++;
    return n;
}

int main()
{
    int ret = Count();
    return 0;
}



struct Array()
{
    int a[10];
    int size;
 }AY;

//引用返回,1.减少了拷贝,返回了一个结构体的成员(出了作用域还在),
int& PosAt(AY &ay,int i)
{
    assert(i<N);
    return ay.a[i];   //出了作用域还在
}

int main()
{
    AY ay;
    PosAt(ay,1);
    //2.调用者修改了这个返回值
    for(int i = 0;i<N;i++)
    {
        count<<PosAt(ay,i)<<endl;
    }

}

总结:如果函数返回时,出了作用域,如果返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统,则必须使用传值返回。

传值,传引用效率比较:

        以值作为参数或者返回类型,在传参和返回期间,函数不会直接传递实参或者变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率很低,尤其当参数或者返回值类型非常大时,效率更低。

5.4引用和指针

1.在语法概念上,引用就是一个别名,没有独立空间,和其引用实体共用 一块空间,在底层实现上实际上是有空间的,因为引用是按照指针方式实现的。

2.引用是定义一个概念的别名,指针存储一个变量地址

3.引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体

4.没有null引用,但有null指针

5.引用在定义的时候必须初始化,指针没有要求

6.在sizeof中的含义不同:引用结果为引用类型的大小,但是指针始终是地址空间所占字节个数(32位下4个字节,64位下8个字节)

7.引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小

8.有多级指针,但是没有多级引用

9.访问实体方式不同,指针需要显式解引用,引用编译器自己处理

10.引用比指针使用相对更安全

6.内联函数

       以inline修饰的函数叫做内联函数,编译c++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提高了程序的运行效率。

6.1内联的特性

        1.inline是一种以空间换时间的做法,如果编译器将函数当做内联函数处理,在编译阶段,会以函数体替换函数调用,优点:少了调用开销,缺点:可能使目标文件变大

        2.inline对于编译器只是一个建议,不同编译器关于inline实现机制不同,一般建议:将函数规模较小,不是递归,且频繁的调用采用inline修饰,否则会忽略inline特性。

        3.inline不要声明和定义分离,分离会导致链接错误,因为inline被展开,没有函数地址了,链接就会找不到。

7.宏

#define N 10


int add(int a, int b)
{
    ...
}

#define Add x+y
#define Add ((x)+(y))

宏的优点:

1.增强代码的复用性

2.提高性能

宏的缺点:

1.不方便调试宏(在预编译阶段进行了替换)

2.导致代码的可读性差,可维护性差,容易误用

3.没有类型安全的检查

C++中可以替代宏:

1.定义常量 换用const,enum. 

2.短小函数换位inline

8.auto关键字(c++11)

     随着程序越来越复杂,程序中用到的类型也更复杂,经常体现在:

       1.类型难于拼写

        2.含义不明确导致错误

      auto 关键字 可以自动推导出变量的类型。使用auto定义变量时,必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。

8.1 auto的使用细则

1.auto与指针和引用结合起来使用

用auto声明指针类型时,用auto和auto*相同,但是auto在声明引用类型时,必须加&

int x = 10;
auto a = &x;
auto* b =&x;
auto&c = x;

2.在同一行定义多个变量

当在同一行声明多个变量的时候,这些变量必须是相同的类型,否则编译器会报错,因为编译器只对第一个类型进行推到,然后用推出来的类型定义其他变量

auto a = 1, b = 2;
auto c = 3, d = 4.0 //err

3.auto不能推的场景

  • auto不能作为函数的参数
  • auto不能用来声明数组

9.基于范围的for循环(语法糖)

9.1范围for的语法

//常规的for循环
void Testfor()
{
    int arr[] = {1,2,3,4,5};
    for(int i =0; i<sizeof(arr)/sizeof(arr[0];++i)
        arr[i] *=2;
    
    for(int *p = arr ;p<array+sizeof(arr)/sizeof(arr[0]);++p)
        cout<<*p<<endl;
}

对于一个有范围的结合,由程序员说明循环的范围是多余的,有时候还会出错,在c++11中引入了基于范围的for循环,for循环后的括号由冒号:分为两部分,第一部分是范围内用于迭代的变量,第二部分是表示被迭代的范围

int arr[] = {1,2,3,4,5};
for(auto& e:array)
    e*=2;

for(auto e:array)
    cout<<e<<endl;

9.2范围for的使用条件

1.for循环的迭代返回必须是已知的

2.迭代的对象要实现++和==的操作(后续迭代器中说明)

10.指针空值--nullptr(c++11)

        NULL实际上是一个宏,表示0,有时候初始化为null和0会有歧义,所以新定义了一个关键字nullptr(关键字)


总结

本文主要讲了c++中的一些关键字和小知识点,能力有限,有错误请指正。

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

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

相关文章

【Java基础】注解——自定义注解

什么是注解? Java 注解(Annotation)又称 Java 标注&#xff0c;是 JDK5.0 引入的一种注释机制。 比如我们常见的Override和Deprecated都是注解&#xff0c;注解可以加在类、方法、成员变量等上面&#xff0c;类似于给他们“打标签"。 注解怎么定义? public interface…

华为OD机试真题 JavaScript 实现【百钱买百鸡问题】【牛客练习题】

一、题目描述 公元五世纪&#xff0c;我国古代数学家张丘建在《算经》一书中提出了“百鸡问题”&#xff1a;鸡翁一值钱五&#xff0c;鸡母一值钱三&#xff0c;鸡雏三值钱一。百钱买百鸡&#xff0c;问鸡翁、鸡母、鸡雏各几何&#xff1f; 现要求你打印出所有花一百元买一百…

AM@空间直角坐标系@数量积和向量积@向量的外积在物理学中的相关概念

文章目录 空间直角坐标系坐标面分向量坐标分解式余弦定理数量积的坐标表示公式 向量积向量积的坐标表示公式 向量的外积在物理学中的相关概念物理量ref 角速度和向量积量纲Base unit (measurement)Background&#x1f388;International System of Units&#x1f388;附 表达方…

【ROS】ROS1导航(了解)

1、简述 ROS1导航模块navigation&#xff0c;它从里程计、传感器流和目标姿势中获取信息&#xff0c;并将速度、角速度控制命令发送至差速控制单元。 因为是ROS1&#xff0c;所以下面的内容只是一带而过&#xff0c;没有深入学习总结。详细内容可参考官网&#xff1a;http://…

Spring高手之路5——彻底掌握Bean的生命周期

文章目录 1. 理解Bean的生命周期1.1 生命周期的各个阶段 2. 理解init-method和destroy-method2.1 从XML配置创建Bean看生命周期2.2 从配置类注解配置创建Bean看生命周期2.3 初始化和销毁方法的特性2.4 探究Bean的初始化流程顺序 3. PostConstruct和PreDestroy3.1 示例&#xff…

Scala入门

第1章 Scala入门 1.1 概述 Scala将面向对象和函数式编程结合成一种简洁的高级语言。 语言特点如下&#xff1a; &#xff08;1&#xff09;Scala和Java一样属于JVM语言&#xff0c;使用时都需要先编译为class字节码文件&#xff0c;并且Scala能够直接调用Java的类库。 &#…

Linux进程信号 | 信号处理

前面的文章中我们讲述了信号的产生与信号的保存这两个知识点&#xff0c;在本文中我们将继续讲述与信号处理有关的信息。 信号处理 之前我们说过在收到一个信号的时候&#xff0c;这个信号不是立即处理的&#xff0c;而是要得到的一定的时间。从信号的保存中我们可以知道如果…

CSP-J组初赛历年真题讲解第1篇

一、二进制基础 1.二进制数 00100100 和 00010100 的和是( )。 A.00101000 B.01100111 C.01000100 D.00111000 来源&#xff1a;模拟试题正确答案&#xff1a;D 讲解&#xff1a; 2.在二进制下&#xff0c;1011001()11001101011001( )1100110 A. 1011 B. 1101 C. 1010…

仓库Vuex

1. 搭建vuex仓库 1.1 安装 npm install vuexnext 1.2 引入 创建store文件夹&#xff0c;里面创建index.js&#xff0c;该js文件中写&#xff1a; import { createStore } from vuex // 引入子仓库 import model1 from "./model1.js" import model2 from "…

行为型设计模式05-备忘录模式

&#x1f9d1;‍&#x1f4bb;作者&#xff1a;猫十二懿 ❤️‍&#x1f525;账号&#xff1a;CSDN 、掘金 、个人博客 、Github &#x1f389;公众号&#xff1a;猫十二懿 备忘录模式 1、备忘录模式介绍 备忘录模式是一种行为型设计模式&#xff0c;用于在不破坏封装性的前提…

Spring Resources资源操作

文章目录 1、Spring Resources概述2、Resource接口3、Resource的实现类3.1、UrlResource访问网络资源3.2、ClassPathResource 访问类路径下资源3.3、FileSystemResource 访问文件系统资源3.4、ServletContextResource3.5、InputStreamResource3.6、ByteArrayResource 4、Resour…

H桥级联型五电平三相逆变器MATLAB仿真模型

H桥级联型五电平逆变器MATLAB仿真模型资源-CSDN文库https://download.csdn.net/download/weixin_56691527/87899094 模型简介&#xff1a; MATLAB21b版本 逆变器采用H桥级联的形式连接&#xff0c;加设LCL滤波器&#xff0c;三相负载构成主电路。 采用SPWM调制&#xff0c;可…

不宜使用Selenium自动化的10个测试场景

尽管在很多情况下测试自动化是有意义的&#xff0c;但一些测试场景是不应该使用自动化测试工具的&#xff0c;比如Selenium、WebDriver。 下面有10个示例&#xff0c;来解释为什么自动化在这种情况下使用时没有意义的&#xff0c;我还将为您提供每种方法的替代方法。 01.验证…

TreeView 简单使用

本文主要介绍 QML 中 TreeView 的基本使用方法&#xff0c;包括&#xff1a;TreeView的适用场景&#xff1b; 控件简介 QML TreeView 是 Qt Quick 中的一个组件&#xff0c;用于显示树形结构的数据。它提供了一种以层次结构方式展示数据的方式&#xff0c;其中每个节点可以包含…

ESP32学习之定时器和PWM

一.定时器代码如下&#xff1a; #include <Arduino.h>hw_timer_t *timer NULL; int interruptCounter 0;// 函数名称&#xff1a;onTimer() // 函数功能&#xff1a;中断服务的功能&#xff0c;它必须是一个返回void&#xff08;空&#xff09;且没有输入参数的函数 //…

【动态规划】路径问题

冻龟算法系列之路径问题 文章目录 【动态规划】路径问题1. 不同路径1.1 题目解析1.2 算法原理1.2.1 状态表示1.2.2 状态转移方程1.2.3 初始化1.2.4 填表顺序1.2.5 返回值 1.3 编写代码 2. 不同路径Ⅱ2.1 题目解析2.2 算法原理2.2.1 状态表示2.2.2 状态转移方程2.2.3 初始化2.2.…

性能测试学习之数据驱动性能测试

了解数据驱动测试理念、能够如何在jmeter中用多种方式实现数据驱动测试。 知识点&#xff1a;字符串拼接、计数器、循环控制器 1. 数据驱动的理念 1.1 定义 从数据文件中读取测试数据,驱动测试过程的一-种测试方法数据驱动可以理解为更高级的参数化 1.2 特点 测试数据与测试…

【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)

目录 1、socket套接字介绍2、字节序简介字节序转换函数 3、socket地址专用socket地址 4、IP地址转换函数5、套接字函数6、TCP通信实现&#xff08;服务器端和客户端&#xff09; 橙色 1、socket套接字介绍 所谓套接字&#xff0c;就是对网络中不同主机上的应用进程之间进行双…

深入理解深度学习——Transformer:整合编码器(Encoder)和解码器Decoder)

分类目录&#xff1a;《深入理解深度学习》总目录 相关文章&#xff1a; 注意力机制&#xff08;Attention Mechanism&#xff09;&#xff1a;基础知识 注意力机制&#xff08;Attention Mechanism&#xff09;&#xff1a;注意力汇聚与Nadaraya-Watson核回归 注意力机制&…

国内唯一可以在本地搭建Stable Diffusion WebUI教程-安装时无需魔法安装全程流畅到尖叫

Stable Diffusion是什么 Stable Diffusion简称SD是一款Ai图片生成工具。“输入几句话,生成精美图片。” 比如说我一开头这幅图片就是用的SD生成的。 我在我的“ChatGPT让我变成了“超人”-如何提升团队30%效能质量提高100%的阶段性总结报告”里提到过midjourney,但是midjou…