c++学习笔记(三)—— 语法/关键字

语法/关键字

auto

通过变量的初始值来推断变量的类型

逗号运算符

逗号运算符的结果是右侧表达式的结果

显式转换

语法:cast-name(expression)

cast-name:

  • static_cast: 任何具有明确定义的类型转换,只要不包含底层const,都可以用。可以通过void*实现类型拆箱封箱操作
  • dynamic_cast: 将基类的指针或引用安全地转换成派生类的指针或引用
  • const_cast: 只能改变运算对象的底层const。比如const char*转string会报错
  • reinterpret_cast: 用于进行各种不同类型的指针之间、不同类型的引用之间以及指针和能容纳指针的整数类型之间的转换。转换时,执行的是逐个比特复制的操作

decltype

获取指定变量类型

int a = 0;
delctype(a) b = 0;  // 等于int b = 0

bind

#include<functional>
using std::placeholders::_1;
bool Check(string &s, size_type sz);

auto check = bind(Check, _1, 6);
check(s); // = Check(s, 6)

ps: 拷贝引用参数的时候,需要用ref

ostream& print(ostream& os,  char c)
{
    return os << c;
}
bind(print, ref(os), _1, ' ');

mem_fn

functional库里

Math obj(1, 2);
auto f = mem_fn(&Math::GetY);
cout << f(obj) << endl;

引用界定符

如果对临时变量调用方法时,会导致语句的失效,比如下面情况:

Tracer t1("Hello");
Tracer t2("cpp");
printf("-----------------\n");
(t1 + t2).setTest("How about setText");
printf("-----------------\n");

(t1 + t2)返回的是一个临时的右值对象,运行完毕后销毁对象,然后这个方法就没啥用了。
引用界定符就是对非static函数加一个限制,使得右值对象不能调用setText方法。手段也很简答,只要在方法签名后面加一个&,就可以通知编译器,这个函数只对左值(引用)有效:

//这里的&表示:只有可修改的左值能调用此函数
void setTest(const char *text) & {
    printf("%d => %s\n", m_text.c_str(), text);
    m_text = text;
}

注意点1:这个符号和const可以同时用,但是const必须在&前
注意点2:只能用于非static的成员函数

花括号赋值

StrVec &StrVec::operator=(initializer_list<string> li)
{
    // 分配内存空间并从给定范围内拷贝元素
    auto data = alloc_n_copy(li.begin(), li.end());
    free();
    elements = data.first();    //更新数据成员使其指向新空间
    first_free = cap = data.second;
    return *this;
}

重载后置递增运算符

后置和前置重载的都是同一个符号,但是参数上有点差别:编辑器会提供一个0的形参

StrBolbPtr operator++(int); //后置运算符
StrBolbPtr& operator++();   //前置运算符

类型转换运算符

可以让类类型隐式转换成自定义的类型

class SmartInt
{
    int val = 0;
public:
    operator int() const {return val;}
};

隐式转换在某些情况下可能会出现莫名其妙的bug,所以可以改成显示转换

class SmartInt
{
    int val = 0;
public:
    explicit operator int() const {return val;}
};
SmartInt si = 3;
static_cast<int>(si) + 3;

allocator

对new和delete使用上的扩展:在内存分配时,和对象构造分开

使用:

  • allocator a
  • a.allocate(n)
  • a.deallocate(p, n)
  • a.construct(p, args)
  • a.destroy(p)
  • uninitialized_copy(b, e, b2) - 迭代器拷贝
  • uninitialized_copy(b, n, b2) - 批量拷贝
  • uninitialized_fill(b, e, t)
  • uninitialized_fill(b, n, t)

NODEBUG 预处理变量

如果定义了NODEBUG,assert将什么也不做

  1. __func__: 当前函数名
  2. __FILE__: 存放文件名
  3. __LINE__: 当前行号
  4. __TIME__: 存放文件编译时间
  5. __DATE__: 存放文件编译日期

constexpr

用来表达在编译时就能算出来的值

控制浮点数打印精度

cout.precision(3);
cout << cout.precision() << " " << sqrt(2.0);
// 输出; 12 1.41

noexcept

c++11关键字,说明修饰的函数不会抛出异常

void recoup(int) noexcept;
void recoup(int) noexcept(true);
void recoup(int) throw();  //c++早期写法,和上面等价
  • noexcept(e):如果e调用的所有函数都做了不抛出说明,且e本身不含throw语句时,该表达式为true

noexcept有两层含义:当跟在函数参数列表后面时,他是异常说明符;而当作为noexcept异常说明的bool实参出现时,它是一个运算符

void recoup(int) noexcept(noexcept(recoup(3.14)));
posted @ 2022-01-17 00:40  二律背反GG  阅读(48)  评论(0编辑  收藏  举报