c++拾遗

constexpr

对const对比,const的值允许在运行后确定,但是constexpr不允许

const int a = get_sz();
constexpr int b = get_sz(); // 如果get_sz()不是constexpr函数,则编译出错

auto与decltype

  • 普通的auto会忽略顶层const和引用
  • auto&会保留顶层const,auto&a = 42(推断为int&)是错的,前面要加const得到 const int&
  • decltype会保留顶层和底层const和引用
  • decltype(*p)得到的是引用类型
  • decltype((expr))永远都是引用类型

类型转换

数组转换

  • decltype不会将数组转换为首元素的指针,故其得到的类型为数组
  • sizeof也不会把数组转换为首元素的指针,故得到的为整个数组大小(字节为单位)

指针转换

  • 0或字面值nullptr能转换为任意指针类型
  • 任意非常量指针能转换void*
  • 对象指针能转换为const void*

类类型转换

比如将字符串赋值给string,由编译器自动执行,但是不能多次

强制类型转换

static_cast<>()

常用于将void*转换成本来的指针类型(由开发者自己保证类型是正确的,否则是未定义的),或者用于基本类型之间的转换

const_cast

  • 只能改变底层const(底层指的是指针指向一个常量,顶层指的是指针本身是常量)
  • 不能用于类型转换,其他转换不能改变const属性

reinterpret_cast

基于更加底层的位模式转换,依赖于机器,应当尽可能避免,其无视任何限制

函数

数组形参

指针式传递

这种方式,编译器把数组当成指针

void print(const int* p);
void print(const int p[]);
void print(const int p[10]); // 10仅仅是我们期望的,编译器会忽略,均等效与const int*

引用式传递

void print(int & a[10]); // error,这代表数组是10个int 引用,这个不符合语法会编译错误
void print(int (&a)[10]); // ok, a是引用一个大小为10的数组,注意此时,10会被编译器考虑

务必小心括号问题,少括号会产生另外一种语义

void print(int * matrix[10]); // 等效于int ** matrix
void print(int (*matrix)[10]);// 指向一个含有10个元素的数组, 10会被考虑 int (*)[10]
void print(int matrix[][10]);// 与上面等效

重载和const形参

  • 编译器无法区分有无顶层const,所以常量和顶层const无法同时存在
  • 但底层const(指针或者引用)可以重载,编译器优先把非常量传给非const重载版本

函数指针

  • 当为形参的时候,函数类型会被自动转换为函数指针
  • 当作为函数指针的时候,函数类型不会被转换为函数指针,c++不允许返回函数类型
void demo(int, int);
using decltype(demo) = Func; // Func是函数类型
using decltype(demo)* = FuncPointer;// 指针类型
Func f(Func g); // error
Func* f(Func g); FuncPointer f(Func g); // ok, 形参里的Func会被转换为函数指针

关键字

  • mutable 允许在const成员函数里面修改变量

前向声明

class A;
class B
{
	A a; // error
    B b; // error
    A& c; // ok
    A* d;// ok;
    static B e; // ok
    static A f; // ok
};

友元说明

注意类里面的友元说明仅仅是声明了访问权限,即便友元函数定义在类内部,也必须在外部声明,否则即便是类的成员函数也无法访问

class A
{
public:
    friend void f(){cout << "f was called!\n"};
    void gg(){f();} // error, f还未被声明
    void hh();
};
void f();
void A::hh(){f();} // ok

静态类成员

  • 必须在外部声明类静态成员变量,否则无法使用,类外声明是无需再写static关键字,但数据类型要写如 int A::w = 10;
  • 若想在类内初始化类内静态变量,必须将其声明为常量const/constexpr
  • 对于在类内提供初值的常量静态成员变量,我们也应该在类外声明一下(但不要提供初值)

delete声明符作用与析构函数

此时只能使用new创建对象,且无法delete释放

构造/析构函数调用虚函数

  • 可以理解为虚机制失效,由构造/析构函数所属类确定
  • 因为基类构造先于派生类构造,派生类析构先于基类构造执行

使用using继承构造函数

using可以指示编译器“继承”基类构造函数,这里不是真正的基础,而有编译器自动生成一些构造函数,这些构造函数与基类构造函数有相同的参数列表,如下

derived(pargram):base(pargram)
  • using不会继承默认、拷贝、移动构造函数

  • 对于含有默认参数的基类构造函数,则会生成多个构造函数,每个构造函数形参数量从最多,依次递减到非默认参数数量

    如基类构造函数有两个参数,一个默认,则会生成接受两个参数的和接受左边那个参数的两个构造函数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值