1.代理构造(委托)
一个构造函数可以调用另外的构造函数
class A{
public:
A(): A(0) {}
A(int i):A(i,0){}
A(int i,int j){
num1 = i;
num2 = j;
average = (num1 + num2) / 2;
}
}
注:避免递归调用
例:
class A{
public:
A():A(0){}
A(int i):A(i,0){}
A(int i,int j):A(){}
}
2.不可变对象和类(Immutable Object and Class)
不可变对象:对象创建后,其内容不可改变,除非通过成员拷贝(例,setter设置器)
不可变类:不可变对象所属的类
int main(){
Employee empJack("Jack",Date(1970,5,3),Gender::male);
Date *birthday = empJack.getBirthday();
}
上述的Employee不是不可变类
不可变类的条件
- 所有数据域设置为"私有"属性
- 没有更改器函数
- 没有能够返回可变数据域对象的引用或者指针的访问器
3.声明或者定义静态成员(Declaration and Definition of Static Member)
在类定义中,关键字static声明不绑定到类实例的成员(该成员无需创建对象即可访问)
静态数据成员的定义
- 声明位“constexpr”类型的静态数据成员必须在类中声明并初始化。自C++17起,可以不在类外定义
- 声明位“inline”(C++17起)或“const int”类型的静态数据成员可以在类中声明并且初始化
- 其它必须在类外定义并且初始化,且不带static关键字
静态存成员
静态数据成员具有静态存储器(static storage duration)或者C++11线程存储期特性
静态存期
- 对象的存储在程序开始时分配,而在程序结束时解回收
- 只存在对象的一个实例
- 静态存储器对象未明确初始化时会被自动 “ 零初始化(Zero-Initialization) ”
下实:统计实例个数
class Square{
private:
double side;
static int numberOfObjects;
public:
Square():Square(1.0){}
Square(double side){
this->side = side;
numberOfObjects++;
}
};
//进行定义,初始化为0
int Square::numberOfObjects;
int main(){
Square s1{},s2{5.0};
}
其中,numberOfObjects位于静态区,唯一的实例,所有对象共享。
3.析构函数(Destructor)
对象销毁的时候
- 析构函数不带参数
- 析构函数不能重载
4.友元(Friend)
私有成员无法从类外访问,有时候又需要授权某些可信的函数和类访问这些私有成员
用关键字友元函数或者友元类,打破类的封装
例
class Date{
private:
int year{2019},month{1};
int day{1};
public:
friend class Kid; //声明
friend void print(const Date& d);
};
//在外面定义
void print(const Date& d){
cout << d.year << "/" << d.month
<< "/" << d.day << endl;
}
class Kid{
private:
Date birthday;
public:
Kid(){
cout << "I was born in "
<< birthday.year << endl;
}
};
int main(){
print(Date());
Kid d;
}
5.拷贝构造函数(Copy Constructor)
拷贝构造:用以对象初始化另一个同类的对象
-
声明拷贝构造函数(Copy ctor)
Circle(Circle&); Circle(const Circlr&);
-
调用拷贝
Circlr c1(c1); Circle c1 = c2; Circle c1{c2};
-
例:
class X{
//...
public:
X(const X& ,int = 1);
};
X b(a,0);
X c = b;
-
注意:
这种形式:obj1 = obj2 不是调用拷贝构造函数,这是对象赋值
只有在初始化的 “ = ” 才是拷贝构造
-
隐式声明的拷贝构造函数(Implicitly-declared Copy Constructor)
- 一般情况下,如果程序员不编写拷贝构造函数,那么编译器会自动生成一个
- 自动生成的拷贝函数叫做“ 隐式声明的拷贝构造函数”
- 一般情况下,隐式声明的拷贝构造函数简单地将作为参数的对象中每一个数据域赋值到新的对象中
5.深拷贝(Deep Copy)
-
浅拷贝(Shallow copy)
数据域是一个指针,那么只拷贝指针的地址,而非指针指向的内容
- 创建新对象 的隐式/默认构造函数
- =(为已有对象赋值的的默认赋值运算符)
-
深拷贝
拷贝指针指向的内容
-
例:
class Employee{
private:
std::string name;
Date birthday;
};
Employee e1{"Jake",Date(1999,5,3),Gender::male};
Employee e3{ e1 };
其中,e1中的birthday = Ox3100。
经过拷贝赋值后,e3中的birthday = Ox3100.
此时,两者的birthday指向同一地址。
浅拷贝
-
定制拷贝构造函数(Customizing Copy Constructor)
如何深拷贝 1. 自行编写拷贝构造函数 2.重载赋值运算符
例:
class Employee{
public:
//Employee(const Employee &e ) = default //浅拷贝
Employee(const Employee& e){
birthday = new Date{e.birthday};
}//...
};
Employee e1{"Jake",Date(1999,5,3),Gender::male};
Employee e2{"Anna",Date(200,11,8),Gender::female};
Employee e3{e1}; //cp ctor深拷贝
6.C++的vector类(The C++ vector class)
- 用数组存放数据时,容量大小可变
- vector对象容量可自动增大
例:
vector<int> iV {-2,-1,0};
for(int i = 1; i < 10 ; i++){
iV.push_back(i+1);
}
编码规范:
跌代变量名应该用 i , j , k等。此外,变量名 j , k 应该只被用于嵌套循环
7.原生字符串字面量(Raw String literals)
语法:
R"delimiter( raw_chatacters)delimiter"
#include <iostream>
const char* s1 = R"(Hello
Wordl)";
//s1效果和s2 s3相同
const char* s2 = "Hello\nWorld";
const char* s3 = R"NoUse(Hello
World)NoUse";
编码规范
- 只要能增加可读性,你在编码的时可以不遵守这些编程风格指南
- 如果你有很好的个人理由的话,可以不遵守这些规范
…
8.栈(The StackOfInteger Class)
一种后进先出的数据结构
stack类封装了栈的存储控件并提供操作栈的函数