[C++ Note]
一些在线编辑器
结构化绑定允许多个变量,这些变量使用数组、结构体、pair或元组中的元素以初始化(c+17/20)
例如:
array values{11, 22, 33};
//结构化绑定
auto [x, y, z] { values };
//注意结构化绑定必须使用auto关键字
std::pair m_Pair{"Hello ", 5};
auto [name, num] { m_Pair };
std::cout << "name: " << name << std::endl;
std::cout << "Num: " << num << std::endl;
//还可以结合引用使用
//......
struct Employee
{
/* data */
char name;
int Num;
float Length;
};
Employee emp{.name='C', .Num=10, .Length = 150}; // 指派初始化
/*
* 优点 :如何更改了增加或者更改了成员的顺序等,在一定程度上不会影响初始化内容的错误
*
*/
auto 推断会去除引用和const限定符,所以会创建副本
可以使用 auto& 或 const auto&
工具函数:as_const() 返回其引用参数的const引用版本
decltype 未去除引用和const 限定符
-
explicit 修饰构造函数时,可以防止隐式转换和复制初始化
-
explicit 修饰转换函数时,可以防止隐式转换,但 按语境转换 除外
struct A
{
A(int) { }
operator bool() const { return true; }
};
struct B
{
explicit B(int) {}
explicit operator bool() const { return true; }
};
void doA(A a) {}
void doB(B b) {}
int main()
{
A a1(1); // OK:直接初始化
A a2 = 1; // OK:复制初始化
A a3{ 1 }; // OK:直接列表初始化
A a4 = { 1 }; // OK:复制列表初始化
A a5 = (A)1; // OK:允许 static_cast 的显式转换
doA(1); // OK:允许从 int 到 A 的隐式转换
if (a1); // OK:使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换
bool a6(a1); // OK:使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换
bool a7 = a1; // OK:使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换
bool a8 = static_cast<bool>(a1); // OK :static_cast 进行直接初始化
B b1(1); // OK:直接初始化
B b2 = 1; // 错误:被 explicit 修饰构造函数的对象不可以复制初始化
B b3{ 1 }; // OK:直接列表初始化
B b4 = { 1 }; // 错误:被 explicit 修饰构造函数的对象不可以复制列表初始化
B b5 = (B)1; // OK:允许 static_cast 的显式转换
doB(1); // 错误:被 explicit 修饰构造函数的对象不可以从 int 到 B 的隐式转换
if (b1); // OK:被 explicit 修饰转换函数 B::operator bool() 的对象可以从 B 到 bool 的按语境转换
bool b6(b1); // OK:被 explicit 修饰转换函数 B::operator bool() 的对象可以从 B 到 bool 的按语境转换
bool b7 = b1; // 错误:被 explicit 修饰转换函数 B::operator bool() 的对象不可以隐式转换
bool b8 = static_cast<bool>(b1); // OK:static_cast 进行直接初始化
return 0;
}
模板替换失败并不是错误!
- 依赖倒置原则:高层次的代码(稳定)不应该依赖低层次的代码(变化)、抽象的代码不应该依赖具体的代码。
- 开放封闭原则:类模块应该开放扩展的,而其原先的代码尽量封闭不可改变。
- 单一职责原则:一个类应该仅有一个变化的原因,该变化隐含了它的职责,职责太多时会导致扩展时对代码东拉西扯,造成混乱。
- 替换原则:子类必须能够替换它的基类(IS-A),继承可以表达类型抽象。
- 接口隔离原则:接口应该小而完备,不该强迫用户使用多余的方法。
- 优先使用组合而不是继承:继承通常会让子类和父类的耦合度增加、组合的方式只要求组件具备良好定义的接口。
- 封装变化点:
- 针对接口编程,而不是针对实现编程。
- 依赖注入(DI) 以及依赖反转(IOC)
- 桩函数
- 空对象模式
- Mock对象