C++初阶--C++入门(1)

简介: C++初阶--C++入门(1)


C语言与C++

很多初学者都会把这两门语言进行混淆,但其实这是两种不同的语言,C++相对与C语言,高级了一些;

语法差异:

C语言是一种面向过程的编程语言,它主要注重函数的调用和流程控制。语法比较简洁,代码结构更加直观。

C++语言是一种混合型的编程语言,即支持面向过程的编程方式,还支持面向对象的编程方式。相对于C语言,C++主要引入了类、对象、继承、多态等概念。

标准库:

C语言的标准库提供了基本的操作函数和常用的数据结构、如数组、字符串的处理、文件操作等。

C++语言是C语言标准库的拓展,提供丰富的容器(vector、list等)和算法(排序、查找等),以及输入输出流等功能。

内存管理:

C语言中,需要手动管理内存分配和释放,使用malloc、free等函数进行动态内存的管理。

C++语言引入了析构函数和构造函数,通过new和delete关键字自动管理内存分配和释放,减少了内存泄漏和错误释放的风险。

在C++中,可以完全兼容C语言,可以直接调用C语言编写的库函数和代码。

命名空间

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

在C语言中,

#include<stdio.h>
int printf = 5;
int main()
{
    
    printf("%d", printf);
    return 0;
}

这种做法是错误的,printf是一个打印到屏幕的函数,由于你对变量的命名与函数名一致,就会导致编辑器认为printf就是创建的临时变量,printf函数也就无法使用。

命名空间的定义和使用

命名空间关键字为namespace,它是将全局作用域进行划分,规定出自己的区域,这样同名者就不会进行冲突了。就像你们村有个叫张三的,隔壁村也有个叫张三的,只要你说我们村的张三的,那么就知道你要找哪个张三了。

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

namespace sea
{
    int printf = 10;
    int Add(int left, int right)
    {
    return left + right;
    }
 struct Node
 {
    struct Node* next;
    int val;
 };
}

这样就规定了上面使用的结构体,printf,Add就在sea命名空间内了。

命名空间也是可以嵌套使用的,就像一个大的村子里面,还有很多个小村;

namespace sea1
{
    int a;
    int b;
    int Add(int left, int right)
     {
         return left + right;
     }
    namespace sea2//嵌套
     {
         int c;
         int d;
         int Sub(int left, int right)
         {
             return left - right;
         }
     }
}

对于同样的命名,编辑器会自动规划在同一片区域:

namespace sea1
{
    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;
        }
    }
}
namespace sea1
{
    int a = 10;
    int c;
}

image

将命名空间进行调用,发现两个创建的变量和函数都放到一起,所以可以看出同样的命名空间会自动划分为同样一块区域;

而像a这样的,会报错,出现重定义:

image

对于命名空间的使用,有三种方式,

第一种就是上面的方式:

int main()
{
    //::表示作用域限定符::,对作用域内的函数、变量等进行调用
    printf("%d\n",sea1::a);
}

第二种:使用using将命名空间中某个成员引入

using sea1::b;
int main()
{
    printf("%d\n", sea1::a);
    printf("%d\n", b);
    return 0;    
}

第三种:使用using namespace 命名空间名称 引入

using namespce sea1;
int main()
{
    printf("%d\n", N::a);
    printf("%d\n", b);
    Add(10, 20);
    return 0;    
}

C++的输入输出

对于C++来说,输入输出不只是可以用printf和scanf,

#include <iostream>
using namespace std;
int main()
{
    //直接输出
    cout<<"hello"<<endl;
    //类型不同
    int a = 10;
    cout << a << endl;
    float b = 3.33;
    cout << b << endl;
    //输入
    cin >> a;
    cout << a << endl;
    return 0;
}

image

  1. 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件
    以及按命名空间使用方法使用std。
    2.== cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出==,他们都包含在包含<
    iostream >头文件中。
    3.== <<是流插入运算符,>>是流提取运算符==。
  2. 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。
    C++的输入输出可以自动识别变量类型。
    具体介绍后面章节会说,这里我们只要记住,cout类似于printf一样
    cin类似于scanf

缺省参数

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

void f(int a=10, int b=15, int c=20)
{
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;
}
int main()
{
    //缺省参数
    f();
}

输出:10 15 20

像这种形参中都用成缺省参数,称之为全缺省参数;

f(1, 2, 3);//全缺省参数,可以全部传参
    f(1, 2);
    f(1);

以上这种都可以进行实现;

1 2 3

1 2 20

1 15 20

对于引用缺省参数的函数来说,在进行函数调用传参时,默认从左到右进行传参,像上面f(1)一样,默认就是第一个传参了,其他的都用了缺省参数的调用值;

如果函数成这样:

void f(int a, int b, int c=20)
{
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;
}

称之为半缺省参数

image

会发现,下面两个函数调用都是错误的,因为那些没有使用缺省参数的,你不传参表示没有值传参;

这里要注意,半缺省参数必须从右往左给,因为函数传参时默认是从左到右依次传参。

缺省参数不能在函数声明和定义中同时出现,否则,将会报错:

image

真要选其中一个进行定义,应该在声明中进行缺省参数。

缺省值必须是常量或者全局变量

函数重载

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

int f(int a,float b)
{
    cout << a << endl;
    cout << b << endl;
    return 0;
}
void f(float a)
{
    cout << a << endl;
    //cout << b << endl;
}
int main()
{
    f(1,2.2);
    f(2.2);
}

这种为函数参数个数不同;

image

int f(int a,float b)
{
    cout << a << endl;
    cout << b << endl;
    return 0;
}
void f(float a ,int b)
{
    cout << a << endl;
    cout << b << endl;
}
int main()
{
    f(1,2.2);
    f(2.2,1);
}

这种是函数参数位置不同

image

void f(int a,int b)
{
    cout << a << endl;
    cout << b << endl;
    
}
void f(double a ,double b)
{
    cout << a << endl;
    cout << b << endl;
}
int main()
{
    f(1,2);
    f(2.2,1.1);
}

这种为参数类型不同

image

而这里如果把double改为float的话,会进行报错,这是因为在VS2022中,1.1和2.2默认为double类型的常数,而double可以隐式转化为float或int,编译器就会报错;

解决方法是f(1.1f,2.2f);

引用

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

image

赋值与引用

int main()
{
    int a = 10;
    int& b = a;
    a = 11;
    cout << b << endl;
    //引用相当于别名,别人怎么改,它就怎么改
    return 0;
}

image

如果是赋值的话:

int main()
{
    int a = 10;
    int b = a;
    a = 11;
    cout << b << endl;
    //如果是赋值,一开始指向都是同个数,是相同的地址,一旦其中一个改变,
    //由于同个数有两个变量,所以另一个只能在别的地址开辟存储别的数;
    return 0;
}

image

image

引用在参数上的使用以及注意事项

引用可以应用在函数传参上,,这样函数调用的参数不会额外产生空间,可提高时间效率

int add(int* a, int* b)
{
    return *a + *b;
}
int add(int& a, int& b)
{
    return a + b;
}
int main()
{
    //int a = 10;
    //int b = a;
    //
    int& a1;//注意:引用须初始化变量
    // int& a2=10;//不可引用常量,引用的权限被放大
    //int& c = a;
    //int& d = a;
    int a = 10;
    int b = 20;
    int c=add(&a, &b);//运用到了重载
    cout << c << endl;
    int d=add(a, b);
    cout << d << endl;
    return 0;
}

image

函数返回值的引用

int& Count()
{
    int n = 90;
    
    return n;
}
int main()
{
    int ret = Count();
    int& ret1 = Count();
    
    cout<<ret<<endl;
    cout << ret1 << endl;//局部变量空间被销毁了,但还是输出正确的答案
    cout <<"l" << ret << endl//虽然空间被销毁了,但值还在那个位置上,ret是一个变量,可以使用
    cout <<"l" << ret1 << endl;//临时拷贝被‘l'所占领,ret1输出随机值
    //是因为返回的值是随机值或者临时拷贝
    //该编译器会保留住一个临时拷贝
}

image

以上这种使用方法是错误的,而是在调用函数的变量前加上static或者调用的变量是全局变量,使变量不会随着函数栈帧销毁而销毁,保留变量所属空间去引用才是正确的。

引用与值的时间效率比较

#include <time.h>
struct A { int a[10000]; };
void TestFunc1(A aa) {}
void TestFunc2(A& aa) {}
void TestRefAndValue()
{
    A a;
    // 以值作为函数参数
    size_t begin1 = clock();
    for (size_t i = 0; i < 10000; ++i)
        TestFunc1(a);
    size_t end1 = clock();
    // 以引用作为函数参数
    size_t begin2 = clock();
    for (size_t i = 0; i < 10000; ++i)
        TestFunc2(a);
    size_t end2 = clock();
    // 分别计算两个函数运行结束后的时间
    cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
    cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
    //8:0,传值还需要不断创建参数栈帧和销毁,而引用不用
    
}

常引用

int a = 10;
    //int& b = a;//引用时权限平等
    const int& b = a;//引用时可权限放小
    cout << b << endl;//10
    a = 20;
    cout << b << endl;//20
    //a修改时,b有相当于只读,所读值也会改变
    b = 20;//错误,引用的b虽然同样是a的别名,但是权限只限制于读,即b是无法修改的
    const int c = a;//可以,赋值时c是另一个变量,const把他变为常变量

所以,引用的权限可以平等和放小,但不能放大;就像一个常量不能用int&来进行引用;

相关文章
|
1月前
|
编译器 C++
C++入门12——详解多态1
C++入门12——详解多态1
38 2
C++入门12——详解多态1
|
1月前
|
编译器 C语言 C++
C++入门3——类与对象2-2(类的6个默认成员函数)
C++入门3——类与对象2-2(类的6个默认成员函数)
24 3
|
1月前
|
存储 编译器 C语言
C++入门2——类与对象1(类的定义和this指针)
C++入门2——类与对象1(类的定义和this指针)
30 2
|
1月前
|
C++
C++入门13——详解多态2
C++入门13——详解多态2
80 1
|
1月前
|
程序员 C语言 C++
C++入门5——C/C++动态内存管理(new与delete)
C++入门5——C/C++动态内存管理(new与delete)
68 1
|
1月前
|
编译器 C语言 C++
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
20 1
|
1月前
|
存储 编译器 C++
C++入门3——类与对象2-1(类的6个默认成员函数)
C++入门3——类与对象2-1(类的6个默认成员函数)
33 1
|
1月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
43 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
1月前
|
存储 安全 编译器
【C++打怪之路Lv1】-- 入门二级
【C++打怪之路Lv1】-- 入门二级
23 0
|
1月前
|
自然语言处理 编译器 C语言
【C++打怪之路Lv1】-- C++开篇(入门)
【C++打怪之路Lv1】-- C++开篇(入门)
26 0