C++入门篇

目录

(一)第一个程序

(二)命名空间

(1)C中遇到的问题

(2)引入namespace

(3)命名空间的使用

①指定命名空间访问

②using展开namespace中某个成员

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

(三)C++输入输出

(四)缺省参数

(1)全缺省

(2)半缺省

(3)报错情况

①形参给值&实参给值

②函数声明&定义分离

(五)函数重载

(1)同一作用域同名函数

[(2)或 参数类型不同](#(2)或 参数类型不同)

[(2)或 参数个数不同](#(2)或 参数个数不同)

(六)引用

(1)先给一段使用引用的代码

(2)两者的地址是相同的

(3)区分类似的符号

(4)注意点

①定义引用的时候必须初始化。

②一个引用对应一个引用对象,且不能更改引用对象(和指针有区别)。

Ⅰ.指针更改指向对象

Ⅱ.引用不能更改引用对象

(5)引用的使用

①引用传参

②引用做返回值

(6)const引用

①使用注意点

②临时对象

Ⅰ.

Ⅱ.

Ⅲ.

(7)指针和引用的区分

(七)inline

(1)首先回顾一下宏函数

(2)使用inline

①vs编译器debug版本默认不展开inline(方便调试)。

②我们需要调一下设置,按照如图箭头所示。

③开始调试,转到反汇编

(3)注意点

(八)nullptr

使用场景

(一)第一个程序

cpp 复制代码
#include<iostream>
using namespace std;
int main() 
{
    cout << "hello world" << endl;
    return 0;
}

(二)命名空间

(1)C中遇到的问题

头文件中定义的变量和我们自己定义的变量都是全局变量,存在冲突。

cpp 复制代码
#include<stdio.h>
#include<stdlib.h>

int rand = 10;

int main() 
{
    // error:rand redefinition
    printf("%d\n",rand);
    return 0;
}

(2)引入namespace

我们在全局定义一个自己的namespace:

cpp 复制代码
namespace wyzy
{
    int rand = 10;
    int Add(int num1,int num2) 
    {
        return num1 + num2;
    }
    struct Node 
    {
        int a = 1;
        struct Node* next;
    };
}

如果我们需要输出我们自己的rand:

cpp 复制代码
int main() 
{
    printf("%d\n",wyzy::rand);
    return 0;
}
  1. namespace本质是定义一个域和全局域隔离。
  2. 局部域、全局域、命名空间域、类域都影响编译时语法查找变量的逻辑;局部域和全局域除此之外还会影响变量的生命周期。
  3. namespace只能定义在全局,可以嵌套定义。
  4. 项目工程中各文件中同名namesapce会认为是同一个namesapce。
  5. C++标准库的namespace叫std(standard)。

(3)命名空间的使用

①指定命名空间访问

cpp 复制代码
int main() 
{
    std::cout << wyzy::rand << std::endl;
    return 0;
}

②using展开namespace中某个成员

cpp 复制代码
using wyzy::rand;
int main() 
{
    std::cout << rand << std::endl;
    return 0;
}

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

cpp 复制代码
using namespace std;
int main() 
{
    cout << "hello world" << endl;
    return 0;
}

(三)C++输入输出

  1. 头文件iostream是input output stream的缩写。
  2. std::cin是istream的对象,面向窄字符(还没学到)的标准输入流。
  3. std::cout是ostream的对象,面向窄字符(还没学到)的标准输出流。
  4. std::endl是一个函数,相当于输出一个换行字符+刷新缓冲区(具体还没学)。
  5. <<:流插入运算符;>>:流提取运算符。(这两个符号也是位运算符号)
  6. C++的输入输出可以自动识别变量类型,能够更好支持自定义类型对象的输入输出。
  7. vs系列编译器中,<iostream>中包含了<stdio.h>。

(四)缺省参数

若函数调用时没有给实参,则函数会有一个缺省参数作为默认参数。

(1)全缺省

cpp 复制代码
int Add(int a = 10, int b = 10)
{
    return a + b;
}

int main() 
{
    cout << Add() << endl;

    return 0;
}

这里调用Add()函数,但是a,b的值都没有给出,

因此函数采用缺省值10,10。

最后输出计算结果20。

(2)半缺省

cpp 复制代码
int Add(int a = 10, int b = 10)
{
    return a + b;
}

int main() 
{
    cout << Add(1) << endl;

    return 0;
}

这里调用Add()函数,只给出了a值为1,

因此函数对b值采用缺省值10。

最后输出计算结果11。

(3)报错情况

①形参给值&实参给值

cpp 复制代码
int Add(int a = 10,int b) // !!报错
{
    return a + b;
}

int main()
{
    cout << Add(1) << endl; // !!报错
    
    return 0;
}

这里要注意:

  1. 形参要从左到右给缺省值。
  2. 调用函数的时候,要从左到右给实参。

大家可以自己试一试,怎么样会报错,怎么样不会报错。

②函数声明&定义分离

头文件defaultParameter.h:

cpp 复制代码
int Add(int a,int b);

实现函数文件:

cpp 复制代码
#include "defaultParameter.h"

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

测试文件:

cpp 复制代码
int main()
{
    cout << Add() << endl; // 报错
    return 0;
}

这里必须在头文件里,函数声明的时候给缺省值,函数定义的时候可以省略缺省值。

(五)函数重载

触发函数重载的条件:

(1)同一作用域同名函数

(2)或 参数类型不同

cpp 复制代码
int Add(int a,int b) 
{
    return a + b;
}

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

这里我们定义两个同名函数,一个对整数相加,一个对浮点数相加。

cpp 复制代码
int main() 
{
    cout << Add(1, 2) << endl;
    cout << Add(1.2, 2.11) << endl;

    return 0;
}
  • 当我们实参给整数时,调用Add(int a,int b)。

  • 当我们实参给浮点数时,调用Add(double a,double b)。

(2)或 参数个数不同

cpp 复制代码
void print() 
{
    cout << "1" << endl;
}

void print(char c) 
{
    cout << c << endl;
}

这里我们定义两个同名函数,一个没有参数,一个只有一个参数。

cpp 复制代码
int main() 
{
    print();
    print('2');

    return 0;
}
  • 当我们不给实参时,调用print()。

  • 当我们给一个实参时,调用print(char c)。

(六)引用

引用即给已存在变量取别名。

(1)先给一段使用引用的代码

cpp 复制代码
int main() 
{
    int a = 1;
    int& aa = a;
    
    return 0;
}

(2)两者的地址是相同的

cpp 复制代码
int main() 
{
    int a = 1;
    int& aa = a;

    cout << &a << endl;
    cout << &aa << endl;

    return 0;
}

(3)区分类似的符号

  1. &:前置取地址,后置引用。
  2. *:前置解引用,后置指针。

(4)注意点

①定义引用的时候必须初始化。

cpp 复制代码
int main() 
{
    int& a; // 报错
    
    return 0;
}

②一个引用对应一个引用对象,且不能更改引用对象(和指针有区别)。

Ⅰ.指针更改指向对象
cpp 复制代码
int main() 
{
    int a = 1;
    int b = 2;

    int* pa = &a;
    int* pb = &b;
    pa = pb;

    cout << "pa:" << pa << endl;
    cout << "pb:" << pb << endl;

    return 0;
}

这里pa = pb,pa最后指向了b这块空间。

Ⅱ.引用不能更改引用对象
cpp 复制代码
int main() 
{
    int a = 1;
    int b = 2;

    int& aa = a;
    int& bb = b;
    aa = bb;

    cout << "&aa:" << &aa << endl;
    cout << "&bb:" << &bb << endl;

    return 0;
}

这里aa = bb只是把bb的值赋给aa了。

(5)引用的使用

①引用传参

原先我们写Swap函数:

cpp 复制代码
void Swap(int* pn1,int* pn2) 
{
    int tmp = *pn1;
    *pn1 = *pn2;
    *pn2 = tmp;
}

现在可以用引用传参:

cpp 复制代码
void Swap(int& num1,int& num2) 
{
    int tmp = num1;
    num1 = num2;
    num2 = tmp;
}

主函数输出:

cpp 复制代码
int main()
{
    int n1 = 1;
    int n2 = 2;

    Swap(n1, n2);

    cout << n1 << endl;
    cout << n2 << endl;

    return 0;
}

最后输出的n1,n2的值符合预期。

②引用做返回值

顺便回顾我们在数据结构中,对于栈的实现。

cpp 复制代码
typedef int STDataType;
typedef struct Stack
{
    STDataType* arr;
    int capacity;
    int top;
}ST;

void STInit(ST& s,int n = 4) 
{
    assert(&s);
    s.arr = (STDataType*)malloc(n * sizeof(STDataType));
    s.capacity = n;
    s.top = 0;
}

void STPush(ST& s, STDataType x)
{
    assert(&s && s.arr && s.top >= 0);
    if (s.capacity == s.top) 
    {
        //...
    }
    s.arr[s.top++] = x;
}

int& STTop(ST& s) 
{
    assert(&s && s.arr && s.top > 0);
    return s.arr[s.top-1];
}

void destroy(ST& s)
{
    assert(&s && s.arr);
    free(s.arr);
    s.arr = NULL;
    s.capacity = 0;
    s.top = 0;
}

int main() 
{
    Stack s;
    STInit(s);
    STPush(s, 1);
    STPush(s, 2);

    cout << STTop(s) << endl;
    ++STTop(s);
    cout << STTop(s) << endl;

    destroy(s);
    return 0;
}

这里STTop的返回值为int&,我们可以直接改变这个返回值,以达到改变栈顶元素值的目的。

(6)const引用

①使用注意点

cpp 复制代码
int main()
{
    const int a = 1;
    int& aa = a; // 报错

    return 0;
}

访问权限在引用过程中只能缩小或不变,不能放大。

不过这里涉及临时对象的问题。

②临时对象

临时对象相当于已经被const修饰了,如果要定义它的引用,只能用const引用。

Ⅰ.
cpp 复制代码
int a = 1;
int& aa = a * 2; // 报错
cpp 复制代码
int a = 1;
const int& aa = a * 2; // 不报错

在这里 a*2 的结果保存在临时对象中。

Ⅱ.
cpp 复制代码
double d = 12.3;
int& dd = d; // 报错
cpp 复制代码
double d = 12.3;
const int& dd = d; // 不报错

在这里12.3类型转换的结果保存在临时对象中。

Ⅲ.
cpp 复制代码
int Add(int a,int b) 
{
    return a + b;
}

int main() 
{
    int& aa = Add(1,1); // 报错

    return 0;
}
cpp 复制代码
int main() 
{
    const int& aa = Add(1,1); // 不报错

    return 0;
}

这里a + b的结果保存在临时对象中。

(7)指针和引用的区分

  1. 在语法上,指针需要开辟新空间,引用和引用对象共用一块空间(具体还没学到)。
  2. 在语法上,指针定义的时候可以不初始化(建议初始化),引用必须初始化。
  3. 指针可以改变指向对象,引用不能改变引用对象。
  4. 指针需要解引用才能真正访问指向对象,引用可以直接访问引用对象。
  5. 指针容易出现空指针和野指针的问题,引用很少出现这些问题。

(七)inline

inline是针对宏函数设计出来的语法。

(1)首先回顾一下宏函数

cpp 复制代码
#define Add(a,b)((a)+(b)) 
cpp 复制代码
int main() 
{
    int add = Add(1,2);
    
    return 0;
}

我们调用宏函数的时候,这个函数会原地展开,替换成((1)+(2))。

(2)使用inline

cpp 复制代码
inline int Add(int x,int y) 
{
    return x + y;
}

int main() 
{
    int add = Add(1, 2);
    cout << add << endl;
    
    return 0;
}

我们通过汇编观察程序是否展开:

①vs编译器debug版本默认不展开inline(方便调试)。

②我们需要调一下设置,按照如图箭头所示。

③开始调试,转到反汇编

可以看到call指令被展开了

(3)注意点

  1. 代码稍微多一点的inline函数不会被展开,具体取决于编译器(大家可以自行尝试多少代码量不会被展开)。
  2. inline函数不建议声明和定义分离到两个文件,会报错。

(八)nullptr

  1. 在C中NULL被定义为无类型指针(void*)的常量,在C++中常被定义为整数常量0。
  2. 当我们需要用到空指针(可以转换成任意其它类型的指针),就可以用到关键字"nullptr"(C++11引入)

使用场景

有两个同名函数:

cpp 复制代码
void f(int x) 
{
    cout << "f(int x)" << endl;
}

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

想要使用NULL调用f(int* ptr),结果却调用到了f(int x):

cpp 复制代码
int main() 
{
    f(0);    // 输出:f(int x)
    f(NULL); // 输出:f(int x)
}

如果我需要用NULL调用f(int* ptr),得给NULL类型转换:

cpp 复制代码
f((int*)NULL); // 输出:f(int* ptr)

我想省事一些,因此选择nullptr

cpp 复制代码
f(nullptr); // 输出:f(int* ptr)
相关推荐
量子炒饭大师2 小时前
【C++入门】零域终端的虚空指针协议——【nullptr】还在为编译器给NULL匹配为int而头疼?nullptr给予你全新的字面量!
开发语言·c++·nullptr
阿豪只会阿巴2 小时前
【多喝热水系列】从零开始的ROS2之旅——Day10 话题的订阅与发布1:Python
开发语言·c++·python·ubuntu·ros2
羊小猪~~2 小时前
【QT】--文件操作
前端·数据库·c++·后端·qt·qt6.3
2501_940315263 小时前
【无标题】1.17给定一个数将其转换为任意一个进制数(用栈的方法)
开发语言·c++·算法
fpcc3 小时前
C++23中的模块应用说明之五综合应用和重点分
c++·c++23
xiaoye-duck4 小时前
吃透C++类和对象(下):内部类、匿名对象及编译器优化的深度解析
c++
情缘晓梦.4 小时前
C++ 内存管理
开发语言·jvm·c++
恒者走天下4 小时前
研一、大一大二学计算机应该怎么规划
c++
我是一只小青蛙8885 小时前
Windows下MATLAB与C++混合编程实战
c++