C++基础

命名空间

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

namespacs dog//命名空间为dog
{
  void print(int a)
  {
    printf(" %d \n", a);
  }
  int a;
  int b;//可定义变量,也可定义函数
  
  namespace big_dog//可以嵌套
  {
    void fun1(int a)
    {
      printf("%d\n", a);
      int a;
      int b;
    }
  }
}

命名空间成员使用方式:

  1. 命名空间+::+成员(推荐使用这种方式 )
  2. 引入成员 using+命名空间+::+成员:
    后面使用成员时,不需要加作用域,成员暴露在全局域中,如果全局域中有同名成员,会导致命名冲突
  3. 展开命名空间using+命名空间:命名空间中所有的成员暴露在全局域中

C++输入输出方式

头文件+std命名空间 不需要显示指定输入输出变量的格式,支持连续的输入输出(c++头文件没有.h; c才有.h)
输出:std::cout<< a <<"\n";(支持连续输出)
输入:std::cin>>b>>a;(支持连续输入)

缺省参数

给参数定义一个默认值,实际使用时,如果没有传参,对应的形参使用默认值。
传参:参数要连续的给,必须从左向右依次赋值,中间不能有间隔。
全缺省:全部参数缺省值
半缺省:部分参数缺省值(必须从右向左依次连续赋值,中间不能有间隔)
缺省值只能出现在声明或者定义的地方,不能同时出现。

void fun1(int a = 1, int b = 2, int c = 3)//全缺省
{
  std::cout << a << b << c << std::endl;
}
void fun2(int a, int b = 2, int c = 3)//半缺省,必须从右到左连续无间断
{
    std::cout << a << b << c << std::endl;
}
void fun3(int a = 1, int b = 2, int c)//非法
void fun4(int a = 1, int b, int c = 3)//非法
  
//错误写法,缺省值只能出现在声明或定义的地方,不能同时出现
void fun5(int a = 1, int b = 2, int c = 3);//声明
void fun5(int a = 100, int b = 200, int c = 300)//定义
{
    std::cout << a << b << c << std::endl;
}

函数重载

同一个作用域内声明几个功能类似的同名函数,这些同名函数的行参列表(参数个数或类型或顺序)必须不同, 常用于处理实现功能类似数据类型不同的问题。函数名相同,参数不同,且在同一个作用域,c++支持,c不支持(底层编译器的行事规则,c++加入参数信息,C语言没有)。
参数不同:类型,个数,顺序不同。
仅仅是返回值不同,不能构成函数重载。

int Add(int a, int b)
{
	return a + b;
}
float Add(float a, float b)
{
	return a + b;
}
int Add(int a, int b, int c)
{
	return a + b + c;
}
int Add(char a, int b)
{
	return a + b;
}
int Add(int a, char b)
{
	return a + b;
}
void test3()
{
	std::cout << Add((float)1.5, (float)1.6) << std::endl;
}

函数重载如何实现的

int Add(int a = 1, int b = 2)

编译器编译之后的底层函数名称:

  1. VS:C编译器 :无法解析的外部符号 _Add
  2. VS:C++编译器:无法解析的外部符号 ?Add@@YAHH@Z
  3. g++编译器:_Z3Addii
  4. _Z:规定的前缀,3:函数名字的字数,Add:函数名,ii:有两个int类型参数

函数名修饰规则:
C编译器:函数名中不包含参数信息
C++编译器:函数名中包含参数信息

int Add(int a, int b)
//C编译器均为:_Add
//g++编译器:_Z3Addii
float Add(float a, float b)
//_Z3Addff
int Add(int a, int b, int c)
//_Z3Addiii
int Add(char a, int b)
//_Z3Addci
int Add(int a, char b)
//_Z3Addic

extern “C”
extern "c"让编译器按照C语言的编译规则进行编译

extern "C"{
  int sub(int a, int b);
  int mul(int a, int b);
}

引用

引用不是新定义一个新变量,而是给已存在的变量取了个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用一块内存空间。
引用的定义类型+&+引用名称(int& ra = a)

int a = 10;
int& ra = a;
int& ra2 = a;
const int b = 10;
const int& rb = a;
const int& r = 10;
//引用类型和引用实体必须是相同类型
double d = 2.0;
double& rd = d;
int c = d;
const int& rd2 = d;
//d隐式类型转换,生成一个临时int变量,rd2此时指向为此临时变量,而临时变量具有常性

引用定义时必须要初始化,引用定义之后,不会再去更改实体的指向。
引用做返回值:注意返回变量的生命周期一定要大于函数的生命周期

void swap(int& ra, int& rb)
{
	int tmp = ra;
	ra = rb;
	rb = tmp;
}

int& Add2(int& ra)//int& Add3(int a),引用做返回值,注意返回值的周期一定要大于函数生命周期
{
	return ++ra;
}

void test4()
{
	int a = 10;
	int b = 20;
	swap(a, b);
	std::cout << a << b << std::endl;
	int& c = Add2(a);
	std::cout << a << b << std::endl;
}

底层实现原理:引用通过指针实现;定义一个引用类型的变量想当于定义一个指针类型的变量。(可能会变)
语法:引用是别名,不是指针,没有发生拷贝。
引用和指针的不同点:

  1. 引用在定义时必须初始化,指针没有要求;
  2. 引用在初始化是引用一个实体后,就不能在引用其他实体,指针可以在任何时候指向任何一个同类型实体;
  3. 没有NULL引用,但是有NULL指针;
  4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4字节);
  5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小;
  6. 有多级指针,但是没有多级引用;
  7. 访问实体方式不同,指针需要显示解引用,引用编译器自己处理;
  8. 引用比指针使用起来相对更安全。

内联函数

编译器编译时,会进行函数指令的展开,没有栈帧的开销,提高代码的效率。

inline int Add(int a, int b)

代替宏函数实用
inline只是一个建议,编译器会根据实际情况判断,如果代码简单直接展开,如果代码复杂不会展开。inline不支持分离定义

auto

在c++中:自动类型推导,不代表具体的类型,编译时,根据初始化表达式自动推导。

auto a = 2;
auto b = 2.0;
auto c = 'a';
cout << typeid(a).name() << endl;
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;

auto相当于类型的占位符,具体类型在编译时推导。
auto定义的变量必须初始化;auto可以定义多个变量(在定义多个变量时,每一个表达式类型要一致)。
auto a1=3,c1=4;(对) auto a1=3,c1=4.0;(错)因为auto只会推导一次,不会推导多次。
auto对于长类型变量的定义比较简单。
函数参数类型不能使用auto(void fun(auto a,auto b);),定义数组不能使用auto。
auto定义指针时,加不加*没有区别,定义引用类型时,必须加 &。

范围for

要迭代的变量 :要迭代的范围

     int array[ ] = {1,2,3,4,5,6};
     for (int i = 0; i < sizeof(array) / sizeof(array[0]; ++i)
            cout<<array[i]<<" ";
     cout<<endl;
范围for
      for(auto e : array)
           cout <<e << " ";
       cout<<endl;

数据范围确定可以用范围for,不确定不可以用。

指针空值nullptr

  1. 其作为关键字,不需要包含头文件
  2. sizeof(nullptr) == sizeof ((void*) 0 )
  3. 为了提高代码健壮性,尽量使用nullptr表示指针空值
int* p = NULL; // int* p = 0;
int* p2 = 0; //和上面指令没有区别
fun(NULL); //编译器默认NULL为整形的0,而不是指针空值。
fun((int*)NULL); //NULL:二义性,指针空值,整形0
fun(nullptr); //nullptr可以隐式转换成任意指针类型(内置和自定义)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值