C++基础知识

C++关键字

C++命名时,不可使用关键字进行命名,否则系统直接报错,关键字是C++语言本身设定好的,有其各自的用途。C++中共包括63个关键字。
在这里插入图片描述

命名空间

定义

命名空间定义是所使用的关键字是

namespace //后边紧接的是所命名的空间的名字

例如在C++中,我们需要在开头添加

using namespace std;//空间的名字为std

又例如普通的命名空间

namespace A1
{
    int a ;
    int add(int b,int c)
    {
        return b+c;
    }
}

命名空间的使用

我们定义完一个空间之后,有时需要使用到所命名空间中的成员,所以此时我们使用命名空间。

第一种(加命名空间名称及作用域限定符)

我们以定义中所举的普通命名空间为例子:

namespace A1
{
    int a ;
    int add(int b,int c)
    {
        return b+c;
    }
}
int main()
{
  printf("%d\n",A1::a);
  return 0;
}

第二种(使用using将成员引入)

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

第三种(使用using namespace引入)

//1、
include<iostream>
using namespace std;
//2、
using namespace N;
int main()
{
  printf("%d\n",A1::a);
  printf("%d\n",b);
  return 0;
}

C++的输入和输出

在学习c语言时,我们所使用的输入和输出是scanfprintf。这两个函数都是包含在头文件

#include<stdio.h>

而在C++中,我们所使用的输入和输出分别是cincout,而这两个标准输入和输出需要包含一个头文件和一个命名空间,

#include<iostream>
using namespace std;

如下所示,打印输出Hello C++!

#include<iostream>
using namespace std;

int main()
{
  cout <<"Hello C++!"<<endl;
  return 0;
}

又例如输入实现两个整形相加的功能

#include<iostream>
using namespace std;

int main()
{
    int a ;
    int b ; 
    cin >> a ;
    cin >> b ;
    cout << "sum =" << a + b <<endl;
    return 0;
}

运行结果如下图所示:
在这里插入图片描述

函数重载

重载的概念

函数重载就是说允许在同一作用域下使用多个同名的函数,但是这些函数需要满足一定的条件,满足以下三个条件即可实现函数的重载。

  1. 参数个数不同
  2. 参数的类型不同
  3. 参数的顺序不同

如下代码 即为函数的重载:

#include<iostream>
using namespace std;

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

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

long add(long a , long b )
{
   return a + b ;
}

int main()
{
  add(1,2);
  add(1.0,2.0);
  add(1L,2L);
  return 0;
}

需要注意的一种情况是,如果函数参数书的个数、类型、顺序都相同,只有返回值不同的话,则不满足函数重载的条件,所以函数不会重载。如下代码所示:

#include<iostream>
using namespace std;

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

long add(int a , int b )
{
   return a + b ;
}

为什么C++中可以发生重载

在学习c语言是,当两个函数发生重名时,会直接报错,但是在C++中就可以发生函数的重载。
(仅个人理解)
这是因为在c语言中,函数名和地址会链接在一起,例如

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

在c语言中,如果创建了一个add的函数,会发生这种情况(地址 ),当创建第二个add函数时,两个同名函数会指向同一个地址,这时如果调用的话,编译器不知道所调用的是哪个函数。如果是在c++中,当创建了如下两个函数

int add(int a, int b)
{
  return a + b;
}
double add(double a, double b)
{
  return a + b;
}

虽然函数名字相同,但是c++在创立这两个函数时,并不是将函数名和地址绑定,而是(地址 <_Zxxxii>和地址<_Zxxxdd>)。
所以在c++中可以发生函数的重载,而c语言中不可以发生函数的重载。

缺省参数

简单地说,就是在定义函数后,可以为函数中所调用的参数设定默认值,如果没有设定默认值的话,直接传入此参数的实参。
如下列代码及运行结果所示:

#include<iostream>
using namespace std;

void test1(int a , int b)
{
    cout <<"a ="<< a <<"\t"<< "b = "<< b <<endl;
}

void test2(int a  , int b = 20 )
{
    cout <<"a ="<< a <<"\t"<< "b = "<< b <<endl;
}

void test3(int a = 30  , int b = 30 )
{
    cout <<"a ="<< a<<"\t" << "b = "<< b <<endl;
}

int main()
{
   test1(10,10);
   test2(20);
   test3();
   return 0;
}

在这里插入图片描述

需要注意的是,缺省值不可以间隔着给,必须是从右往左依次给,例如下列代码:

void test2(int a  , int b = 20 )
{
    cout <<"a ="<< a <<"\t"<< "b = "<< b <<endl;
}//此代码可以正常传入实参
void test2(int a =20 , int b )
{
    cout <<"a ="<< a <<"\t"<< "b = "<< b <<endl;
}//此代码不可以正常传入实参

extern “C”

加上extern”C“表明在C++工程中,此函数是按照c语言的风格来编译。

extern "C" int add(int a , int b )
{
  add(1,2);
  return 0;
}//个人不是很理解具体用在何处

引用

引用的定义

类型&别名 = 原名;
例如:

int main ()
{
   int a = 2 ;
   int&b = a;//此时a和b指向同一内存空间
}//要注意引用的类型要和引用实体的类型一致

引用的时候,需要直接进行引用,不可以只定义(不初始化)之后再引用,这样的话会报错。

int main ()
{
   int a = 2;
   int &b;//此行代码会报错
}

对用同一个内存空间,可以有多个别名,例如一下程序:

#include<iostream>
using namespace std;

int main()
{
    int a = 2;
    int& b = a;
    int& c = a;
    int& d = a;
   
   cout<< "a = " << a <<'\n';
   cout<< "b = " << b <<'\n';
   cout<< "c = " << c <<'\n';
   cout<< "d = " << d <<'\n';
   cout <<endl;
    
    return 0;
}

此时的运行结果为:
在这里插入图片描述

可以看出此时abcd都等于2,也就说明了,a此时有了bcd三个别名,这四个都指向同一内存空间。

常引用

1.如果定义一个变量为常量,引用时是不可以用非常量的方式进行引用,否则会报错。

int main ()
{
   const int a = 10;
   int& b = a;//此时a是常量,别名不可以为可读可写,则编译出错
   int& b = 10;//10也为常量,编译会出错
}

2.但是如果定义一个变量为非常量,而用常量的方式进行引用的话,这样是可以的。

int main ()
{
   int a = 10;
   const& b = a;//此时a的权限可读可写,所以可以这样定义。
}

3.引用时,引用类型和引用实体的类型要一致,否则也会报错。

int main ()
{
   double a = 2.5;
   int& b = a ;//引用类型和实体类型不同,编译出错
}

引用传参

引用传参和指针传参以及传值

传值
#include<iostream>
using namespace std;

void swap(int a , int b);

int main()
{
    int a = 1;
    int b = 2;
    swap(a , b);
    cout << "a = " << a << "\t" << "b = " << b << endl;
    return 0;
}

void swap(int a , int b)
{
    int temp;
    temp = a ;
    a =  b ;
    b = temp ;
}

此时运行结果为:
在这里插入图片描述

显而易见,当将实参传入到函数中时,只是将值赋给了形参,对形参的值进行了互换,而对实参并没有任何影响,所以只传值,并不能mian函数中的参数互换。

指针传参
#include<iostream>
using namespace std;

void swap(int* a , int* b);

int main()
{
    int a = 1;
    int b = 2;
    int *a1,*b1;
    a1 = &a;
    b1 = &b;
    swap(a1 , b1);
    cout << "a = " << a << "\t" << "b = " << b << endl;
    return 0;
}

void swap(int* a , int* b)
{
    int temp;
    temp = *a ;
    *a =  *b ;
    *b = temp ;
    cout << "a = " << *a << "\t" << "b = " << *b << endl;
}

指针传参的运行结果:
在这里插入图片描述

可以看到,指针传参之后,是将main函数里实参进行了交换,可以得到我们所需要的结果。
因为在main函数中,先设定了两个整型变量,随后又定义了两个指针指向这两个整形变量,此时再进行传参时,所进行的操作是将两个整形变量的地址传入,对这两个地址上的值进行互换,所以不管是形参还是实参,都进行了互换。

引用传参
#include<iostream>
using namespace std;

void swap(int& a , int& b);


int main()
{
    int a = 1;
    int b = 2;
    swap(a , b);
    cout << "a = " << a << "\t" << "b = " << b << endl;
    return 0;
}

void swap(int& a , int& b)
{
    int temp;
    temp = a ;
    a =  b ;
    b = temp ;
    cout << "a = " << a << "\t" << "b = " << b << endl;
}

此时运行的结果:
在这里插入图片描述

可以看出,在进行引用传参时,形参和实参都进行了交换。引用传参的本质其实就是利用指针进行传参数,而且引用传参用起来会比指针传参方便一些。

引用做返回值

(不推荐引用做返回值,除非返回值是全局区变量,否则不推荐使用)
在这里插入图片描述
c++程序运行时,会将内存分为以上四个区域,假设有一个函数的返回值不是全局变量、静态变量及常量

#include<iostream>
using namespace std;

int& back();

int main()
{
    int& ret = back();
    cout << "a = " << ret  <<endl;
    cout << "a = " << ret  <<endl;
    return 0;
}

int& back()
{
    int a = 2;
    return a ;
}

当写入程序后,会出现警告
在这里插入图片描述
这个警告说明了,不可以用局部变量引用做返回值。因为这个函数的局部变量在定义后,会存放在栈区,当函数运行完成后,此局部变量会被释放,所以引用做返回值,在局部变量释放后,他并不知道自己是谁的别名,从底层来说,也就是指针并不清楚是指向哪块内存空间。
如果我们是将全局区里的变量可以引用做返回值的话,这样是可以的。例如:

#include<iostream>
using namespace std;

int& back();

int main()
{
    int& ret = back();
    cout << "a = " << ret  <<endl;
    //cout << "a = " << ret  <<endl;
    return 0;
}

int& back()
{
    static int a = 2;
    return a ;
}

此时在函数里定义了静态变量a,a是存放在全局区,当函数运行完,a并不会直接被释放,所以可以引用做返回值,此程序的运行结果如下:
在这里插入图片描述

综上所述,当引用做返回值时,一定要注意返回值是什么变量,是否可以引用。

引用和指针的区别

  1. 引用相对于指针来说,在传参的效率上,极大的提高了传参效率。
  2. 引用在定义时必须要进行初始化,而指针可以不用初始化
int main()
{
   int a ;
   int& b = a ;//必须要进行初始化
   int* p;//不用初始化
}
  1. 没有空引用,但是有空指针(NULL)
  2. 在sizeof中的含义不同,引用的结果是引用类型的大小,而指针是地址空间所占用的字节数。
  3. 引用自加即引用的实体增加1,指针自加是指针向后偏移一个数据类型的字节数。
  4. 引用没有多级引用,但是指针有多级指针。
  5. 指针需要解指针,但引用编译器可以自己处理。
  6. 引用比指针使用起来安全一些。

内联函数

以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。
(还没使用过不怎么理解)

auto关键字

(后续补充)

指针空值nullptr

在c++11中,nullptr表示空指针,而NULL是一个宏定义,其包含在了头文件(stddef.h)中

#define NULL 0

所以在传值调用函数时

void f(int)
{
    cout << "f(int)" << endl;
}//NULL会调用此函数

void f(int*)
{
    cout << "f(int *)" << endl;
}//nullptr会调用此函数

而在c++17中,NULL的宏定义发生了改变

#define NULL __null//此处的类型为long long

我们只需记住nullptr是空值指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪好像下整夜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值