1. 字面量
1.1 宏替换——与类型别名对比
#define Monday 1
自定义字面量
// 有错!!!!
int operator""_$ (int a) {
return a;
}
printf("%d", 5_$);
2. 类型
2.1 枚举
-
非匿名枚举类:
enum Week{Monday=1, Tuesday}-
作用域:整个空间内,而非“enum Week”中
-
-
匿名枚举类:
enum {Monday, Tuesday}-
作用域同上
-
-
强类型枚举:
enum class Week {Monday, Tuesday}-
能够进行作用域隔离,引用时
Week::Monday
-
3. 类型基础行为
3.1 初始化
3.1.1 构造式初始化
struct A {
A() {
a = 0;
}
A(int a) {
this->a = a;
}
int a;
}
// 栈对象
A a;
A b(1);
// 堆对象
A *a = new A;
A *b = new A();
A *c = new A(1);
3.1.2 赋值式初始化
struct A {
A(int a) {
this->a = a;
}
int a;
};
int main() {
A a = 1;
}
问题:
-
看起来容易误解成赋值
-
不支持多个入参的构造
-
不支持堆对象的双重初始化:
// 赋值式:error! *(int* ptr = new int) = 5; // 构造式: int *ptr = new int(5);
如果想让构造函数仅支持构造式,不支持赋值式:关键字explicit
struct A {
explicit A(int a) {
this->a = a;
}
int a;
};
int main() {
A a(1);
// error!
// A a = 1;
}
3.1.3 列表式初始化
struct A {
A(int a, int b) {
this->a = a;
this->b = b;
}
int a, b;
};
int main() {
A a {1, 1};
int *pa {new int {1}};
}
3.2 自动类型识别
关键字:auto
auto i = 120; // int
3.3 初始化类成员
-
在构造函数中赋值,是为成员数据“赋值”,而非“初始化”
-
成员初始化列表:
-
位于构造函数函数名与函数体之间,并非“赋值”;
-
可以为构造式或列表式,不能是赋值式
-
初始化顺序:成员变量声明顺序,而非初始化列表中顺序
-
struct A {
A(int a, int b)
: a {a}, b(b)
{}
int a, b;
};
-
成员声明式初始化:
-
可以为赋值式或列表式,不能是构造式
-
C++ 98不允许;C++ 11允许
-
struct A {
int a = 1;
int b {3};
};
3.4 复制构造行为
-
浅拷贝:仅复制目标对象的对应内存,即引用本身的地址
-
深拷贝:拷贝引用的目标对象的全部内容
-
C++默认的拷贝行为是将来源对象的内存内容拷贝
-
如对于栈中变量:
int i;A a;等,进行A b = a;后,b复制了a的全部内容,即深拷贝 -
如对于堆中变量:
A *a = new A();,由于a是指针,b复制的仅是a的指针内容,即浅拷贝
-
3.4.1 定制拷贝代码
struct A {
A(int a)
: a(1)
{}
A(A const& other)
: a(other.a)
{}
int a;
};
3.4.2 堆变量的深拷贝
下类中声明了一个指针,并在堆中为其开空间
struct A {
explicit A(int a)
: pa(new int(a))
{}
~A() {
delete pa;
}
int* pa;
};
// test
A a(1);
A b(a);
cout << a.pa << endl;
cout << b.pa << endl;
在进行test后会发现,b变量的pa地址和a的地址一样,也就是进行了浅拷贝;虽然程序会无法正常推出,这可能是因为A并没有实现A(A const& a){}构造函数。
接下来为A实现深拷贝构造函数:
struct A {
explicit A(int a)
: pa(new int(a))
{}
A(A const& other)
: pa(new int(*(other.pa)))
{}
~A() {
delete pa;
}
int* pa;
};
// test
A a(1);
A b(a);
// 或:A b = a;
cout << a.pa << endl;
cout << b.pa << endl;
在Clang中,新实现的拷贝函数被称为“Copy constructor”,同时,Clang-Tidy希望“Clang-Tidy: Copy constructor should not be declared explicit”。
3.4.3 禁用拷贝构造
struct A {
explicit A(int a)
: pa(new int(a))
{}
A(A const&) = delete;
~A() {
delete pa;
}
int* pa;
};
3.5 赋值行为
3.5.1 初始化与赋值——拷贝构造函数和赋值函数
A a; // 1 A b = a; //2 A b; b = a;
在1中,是对b通过“拷贝构造函数”进行初始化;在2中,第一行完成初始化,第二行利用“赋值函数”进行赋值。
因此上节禁用拷贝构造函数,但仍可以进行赋值(但是进行堆变量的浅拷贝)。
3.5.2 重载“operator=”实现赋值函数深拷贝
struct A {
explicit A(int a)
: pa(new int(a))
{}
A(A const& other)
: pa(new int(*(other.pa)))
{}
A& operator= (A const& other) {
// 1
if (this == &other) return *this;
if (other.pa != this->pa) {
delete this->pa;
pa = new int(*other.pa);
return *this;
}
}
~A() {
delete pa;
}
int* pa;
};
A a(1);
A b(2);
b.operator=(a);
// 更为常用的:b = a;
cout << *a.pa << endl;
cout << *b.pa << endl;
1部分是为了处理自我赋值;
之所以赋值函数返回类型是A&,是为了支持语法a=b=c
3.5.3 禁止赋值
struct A {
explicit A(int a)
: pa(new int(a))
{}
A(A const&) = delete;
A& operator= (A const&) = delete
~A() {
delete pa;
}
int* pa;
};
3.5.4 拷贝构造函数和赋值函数的关系
struct A {
explicit A(int a)
: pa(new int(a))
{}
A(A const& other)
: pa(new int(*(other.pa)))
{
cout << "constructor" << endl;
}
~A() {
delete pa;
}
int* pa;
};
如果没有使用“explicit”修饰拷贝构造函数(使用是不被建议的),那么可能会用拷贝构造函数来进行赋值操作(至少我的编译器不会),一些解决方式:
-
禁用拷贝构造函数
-
将拷贝构造函数使用“explicit”修饰
-
明确重载赋值函数“operator=”
-
将赋值函数“operator=”标为delete
C++编程基础:字面量、枚举、类型初始化与构造/赋值行为详解,
11万+

被折叠的 条评论
为什么被折叠?



