C++| |C/C++11的小语法与知识点

C/C++11的小语法与知识点


 

1.auto

  • 在c/c++早期的时候,auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量

  • auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器。auto声明的变量必须由编译器在编译时期推导而得的

//必须在新的编译器才可以跑过,旧的会出错
​
#include <iostream>
using namespace std;
​
int TestAuto()
{
  return 10;
}
​
int main()
{
  int a = 10;
  auto b = a;\\b是int类型
  auto c = 'a';\\c是char类型
  auto d = TestAuto();\\d是int类型
​
  cout << typeid(b).name() << endl;
  cout << typeid(c).name() << endl;
  cout << typeid(d).name() << endl;
​
​
  //auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化
​
  return 0;
}

【注意】

  • 使用auto定义变量时必须对其进行初始化,在编译阶段编译器根据初始化表达式来推导auto的实际类型,因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”。编译器在编译期间会将auto替换为变量实际的类型。

 

1.1 auto与指针连用

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

    用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&

#include <iostream>
using namespace std;
​
int main()
{
  int x = 10;
  auto a = &x;//int*
  auto* b = &x;//int*
  auto& c = x;//int,引用也是x,所以类型也是int
​
  cout << typeid(a).name() << endl;
  cout << typeid(b).name() << endl;
  cout << typeid(c).name() << endl;
​
  *a = 20;
  *b = 30;
  c = 40;
​
  return 0;
}
  • 同一行定义多个变量

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

void TestAuto()
{
    auto a = 1, b = 2;
    auto c = 3, d = 4.0;//改行代码会编译失败,因为c和d的初始化表达式类型不一样
}

 

auto不能推导的场景

1.auto不能作为函数的参数

//此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
​
void TestAuto(auto a)
{
    
}

2.auto不能直接用来声明数组

void TestAuto()
{
    int a[] = { 1, 2, 3 };
    auto b[] = { 1, 2 };
}

3.auto不能定义类的非静态成员变量

4.实例化模板时不能使用auto作为模板参数

 

2. nullptr和nullptr_t

  • 为了考虑兼容性,c++11并没有消除常量0的二义性,c++11给出了全新的nullptr表示空值指针,c++11为什么不在NULL的基础上进行扩展,这是因为NULL以前就是一个宏,而且不同的编译器商对于NULL的实现可能不太相同,而且直接扩展NULL,可能会影响以前旧的程序,因此,为了避免混淆,c++11提供了nullptr,即:nullptr代表一个指针空值常量。nullptr是有类型的,其类型是nullptr_t,仅仅可以被隐式转化为指针类型,nullptr_t被定义在头文件中:

typedef decltype(nullptr) nullptr_t;

【注意】:

  1. 在使用nullptr表示指针空值的时候,不需要包含头文件,因为nullptr是c++11作为关键字引入的

  2. 在c++11中,sizeof(nullptr) 和sizeof(void* 0)所占字节数相同

  3. 为了提高代码的健壮性,在后续表示空值指针是建议最好使用nullptr

 

3. 在linux下显式的使用c++11

  • 对于一般的linux下的g++编译器都是支持c++98的,如果想让其支持c++11编译的话,那就只需要显式打开c++11就好了

#include <iostream>
#include <typeinfo>
using namespace std;
​
int TestAuto()
{
    return 10;
}
​
class Test
{
public:
    Test(int a = 0)
        : _a(a)
    {}
​
private:
    int _a = 1;//c++11支持对于非静态成员变量直接进行初始化
};
​
int main()
{
    int a = 10;
    auto b = a;
    auto c = 'a';
    auto d = TestAuto();
    Test e;
    auto f = e;
​
    cout << typeid(b).name() << endl;//int
    cout << typeid(c).name() << endl;//char
    cout << typeid(d).name() << endl;//int
    cout << typeid(e).name() << endl;//class Test
    cout << typeid(f).name() << endl;//class Test
​
​
    //auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化
​
    return 0;
}

对于上面的代码,具有c++11的新语法auto,如何对其进行编译呢?

g++ -o auto auto.cpp 
//采用这种编译的话,就显示
//‘b’ does not name a type
//表示该编译器不支持c++11,所以就要显式的使用c++11编译
​
g++ -std=c++11 -o auto auto.cpp
//这种进行编译的话就不会出错,显式的使用c++11

 

4. typeinfo 库

包含typeid().name()工具函数,用来返回变量的数据类型,学习这个函数

typeid操作符,其返回结果名为type_info标准库类型的对象引用type_info存储特定类型的有关信息,定义在typeinfo头文件

typeid().name(),用来获取表达式的类型,以c-style字符串形式返回引用名

【注意】:对于非引用类型,typeid().name()在编译时期识别,只有引用类型才会在运行时识别。

例:

#include <iostream>
#include <typeinfo>
using namespace std;
​
int TestAuto()
{
    return 10;
}
​
class Test
{
public:
    Test(int a = 0)
        : _a(a)
    {}
​
private:
    int _a = 1;//c++11支持对于非静态成员变量直接进行初始化
};
​
int main()
{
    int a = 10;
    auto b = a;
    auto c = 'a';
    auto d = TestAuto();
    Test e;
    auto f = e;
​
    cout << typeid(b).name() << endl;//int
    cout << typeid(c).name() << endl;//char
    cout << typeid(d).name() << endl;//int
    cout << typeid(e).name() << endl;//class Test
    cout << typeid(f).name() << endl;//class Test
    //返回值是char const *,表示该函数的返回值是一个字符串(字符指针)
    cout << typeid(typeid(f).name()).name() << endl;//char const *
​
​
​
    //auto g; 无法通过编译,使用auto定义变量时必须对其进行初始化
​
    return 0;
}

【面试题】:

  • 对于可以使用typeid().name()函数的返回值做为类型名进行定义吗?

    • 不可以

      • 由于typeid().name()函数返回的是一个字符串,肯定不能用于定义

 

5. 内置类型

  • 即某个语言初期的时候定义的类型就叫做内置类型

 

6. delete函数(c++11)

//声明该函数,但是不需要进行实现
HeapType (const HeapType& ht) = delete;

 

7. 匿名对象

//生命周期只有一行
Date d1;//正常对象
Date();//这就是匿名对象

 

8. 定制化的为一个类重载operator new和operator delete

//如果你重载了operator new和operator delete 
//那么该类使用new的时候就会使用你写的operaor new和operator delete
void* operator new(size_t sizt) = delete;
viod operator delete(void* p) = delete;
//没有禁用掉全局和静态的对象产生
​
//对于其他对象new时,不会影响其他对象的new
​

 

9. size_t

无符号整数类型

size_t是sizeof运算符返回的类型,广泛应用于标准库中以表示大小和计数

 

10. C++不加.h

对于C++加不加.h,其实都是可以的,C++的标准是不需要加.h的,比如C语言中的stdio.h和string.h,在C++中就是stdio和string或者cstdio和cstring。加了C之后表示该头文件是从C语言演变过来的,对于C的那是字符串函数,而对于C++那是string对象

 

11. getline的用法

//从流cin中读取数据,写到str中,直到遇到delim
istream& getline(istream& cin, string& str, char delim);
​
//从流中读取数据写到str,默认遇到空格或者换行终止
istream& getline(istream& cin, string& str);

【作用】

​ 对于该全局函数,包含在string头文件中

​ 从流中读取数据,是不会读取到分隔符,只会讲终止符前面的数据读取到str中

 

12. cin.getline的用法

//默认的分隔符为空格或者换行
istream& getline(char* s, streamsize n);//streamsize是有符号字符大小
​
//分隔符为delim
istream& getline(char* s, streamsize n, char delim); 

【作用】

​ 对于该函数是属于cin的

​ 直接从cin中读取字符,直到遇到分隔符停止,或者已经将n个字符写入到s中,实际是读入n-1个字符,最后一个是终止符。(包括终止定界符)

 

13. 为什么main函数会有返回值

平常看到的mian函数都会有着自己的类型,都是int类型

int main()
{
    return 0;
}

对于main函数为什么要有着自己的返回值

  • 由于main函数也是一个进程运行起来的话,对于一个进程当其运行的时候,那么该进程肯定就会有着自己的父进程,那么当main函数结束的时候,父进程就要知道main函数的退出状态,所以就要有着返回值了。对于这个返回值一般都是0,返回0的话,默认该进程执行成功,正确返回。

  • 所以main函数的返回值一般都是0(return 0)

  • 如果不写return 0的话,那么对于c99之后的编译器都会自己默认返回0

 

14. 测试vector的增容情况

//测试vector自我开辟容量的
#include <iostream>
#include <vector>
​
int main()
{
  std::vector<int> varray;
  size_t sz = varray.capacity();
  
  std::cout << "test vector capacity!" << std::endl;
  for (size_t i = 0; i < 1000; i++)
  {
    varray.push_back(i);
​
    if (varray.capacity() != sz)
    {
      sz = varray.capacity();
      std::cout << "capacity change:" << sz << '\n';
    }
  }
​
  return 0;
}
  • 对于在g++下和VS2017下STL库中的vector容器增容的方法是不一样的:

  • 对于g++下:(SGI版本的STL)

    • vector是按照2倍增容的

  • 对于VS下:(PJ版本的STL)

    • vector是按照1.5增容的

 

15. 对于for+auto遍历容器

对于使用for+auto语法糖 遍历一个容器的时候需要什么东西呢?

首先肯定是需要迭代器的。

  • 但是都需要什么迭代器呢?

  • 今天突然写到这个的一个代码。就是对于vector容器的自我实现

  • 由于vector容器实现的时候需要三个模板指针,_start, _finish, _endofstorage

  • 这三个模板类型的指针,分别代表的意思是

    • _start:vector容器的起始地址

    • _finish:vector容器所包含大小的下一个地址也就是, _start+size();

    • _endofstorage:vector容器的最大容量的下一个地址, _start + capacity();

  • 那么我写了这个的一个代码。写了一个赋值运算符重载

  • 我写的时候,忘了对于_finish进行增加,导致最后的时候,_finish和 _satrt是相等的,都指向该vector容器的开头,

  • 然后我再用三种不同的方法进行遍历:

    • for+auto(需要使用迭代器)

    • for+[](不需要使用迭代器)

    • for+iterator(需要使用迭代器)

  • 这三种方法分别遍历:

  • for + iterator遍历for+auto进行出错。对于for + [],这个肯定是正确的

  • 说明对于for+iterator和for+auto都是需要begin()迭代器和end()迭代器

 

16. 在一个类型后面直接加上()表示啥意思

对于这个()表示的的意思就是创建了一个对象。并且将该对象初始化为0.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值