对象和类
过程性编程/面向对象编程(Object-oriented programming,OOP)
抽象/封装/数据隐藏
访问控制
- public
- protected(成员函数/子类)
- private(默认,成员函数/友元类/友元成员函数)
访问控制
静态数据成员
- 定义必须出现在类的外部而且只能定义一次
静态成员函数
- this指针指向用来调用成员函数的对象(被作为隐藏参数传递给方法)
- 非静态成员函数有this指针,而静态成员函数没有this指针.由此决定了静态成员函数不能访问本类中的非静态成员
class Base {
int a;
static int b;
static int func() {
a;//no
b;//yes
object.a;//yes
return 0;
}
};
int Base::b;
Base::func();
Base c;
c.b;
c.func();
对象的存储空间
- 非静态成员变量总和加上编译器为了CPU计算做出的数据对齐处理和支持虚函数所产生的负担的总和
- 1Byte
派生/继承
基类(父类)—>派生类(子类)
- 公有继承
- 保护继承
- 私有继承
派生类的构造函数和析构函数
- 基类构造函数
- 成员类对象构造函数
- 派生类构造函数体
多态(公有继承)
具有多种形态,即同一个方法的行为随上下文而异
- 在派生类中重新定义基类的方法
- 使用虚方法
静态绑定/动态绑定
将源代码中的函数调用解释为执行特定的函数代码块被称为函数名绑定(binding)
静态绑定(static binding)/早绑定(early binding)
编译期
- C,no函数重载
- C++,函数重载(同名函数的形参(?实参)(个数/类型/顺序)必须不同)
动态绑定(dynamic binding)/晚绑定(late binding)
运行期
class Shape {
public:
//静态绑定
int perimeter() {
return 0;
}
//虚函数,动态绑定
virtual int area() {
return 0;
}
//纯虚函数
virtual int vertex() = 0;
};
class Triangle : public Shape {
public:
int perimeter() {//hide
return 3;
}
int area() {//override
return 2;
}
int vertex() {
return 3;
};
};
class Rectangle : public Shape {
public:
int perimeter() {//hide
return 4;
}
int area() {//override
return 4;
}
int vertex() {
return 4;
};
};
int main() {
Shape *shape;
Triangle tri;
Rectangle rec;
shape = &tri;
cout << shape->perimeter() << endl;//0,静态绑定
cout << shape->area() << endl;//2,动态绑定
shape = &rec;
cout << shape->perimeter() << endl;//0
cout << shape->area() << endl;//4
return 0;
}
编译器处理虚函数的方法
- 给每个对象添加一个隐藏成员->虚函数指针(vptr)->虚函数表(virtual function table,vtbl)
编译器处理虚函数的方法
有关虚函数注意事项
- 构造函数不能是虚函数
- 析构函数应当是虚函数,除非类不用做基类
- 友元不能是虚函数,因为友元不是类成员,而只有成员才能是虚函数
智能指针
内存泄漏(memory leak)->析构函数->悬挂指针
- 深复制
- 所有权(ownership,auto_ptr/unique_ptr)
- 引用次数(reference counting,shared_ptr)
explicit(显示)构造函数,指针作为参数
explicit
auto_ptr(deprecated in C++11)
- 行为不确定
- no new[]/delete[]
#include <memory>
auto_ptr<int> a(new int(1));
auto_ptr<int> b;
b = a;// a loses ownership
unique_ptr
- 编译器发出警告
unique_ptr<int> a;
a = unique<int>(new int(1));//临时右值
unique_ptr<int> b;
b = std::move(a)//return a new object
unique_ptr<int[]> c(new int[3]{1, 2, 3});
shared_ptr
- no new[]/delete[]
单例模式
- 懒汉式
class Singleton {
public:
static Singleton *instance();
private:
static Singleton *pInstance;
};
Singleton *Singleton::pInstance = nullptr;
Singleton *Singleton::instance() {
if (pInstance == nullptr) {
pInstance = new Singleton;
}
return pInstance;
}
Singleton *Singleton::instance() {
pthread_mutex_lock(&mutex_x);
if (pInstance == nullptr) {
pInstance = new Singleton;
}
pthread_mutex_unlock(&mutex_x);
return pInstance;
}
- Double-Checked Locking Pattern(DCLP)
Singleton *Singleton::instance() {
if (pInstance == nullptr) {
pthread_mutex_lock(&mutex_x);
if (pInstance == nullptr) {
pInstance = new Singleton;
}
pthread_mutex_unlock(&mutex_x);
}
return pInstance;
}
- DCLP and Instruction Ordering
pInstance = new Singleton;
Step 1: Allocate memory to hold a Singleton object.
Step 2: Construct a Singleton object in the allocated memory.
Step 3: Make pInstance point to the allocated memory.
Singleton *Singleton::instance() {
Singleton *tmp = pInstance;
// insert memory barrier
if (tmp == nullptr) {
pthread_mutex_lock(&mutex_x);
if (tmp == nullptr) {
tmp = new Singleton;
// insert memory barrier
pInstance = tmp;
}
pthread_mutex_unlock(&mutex_x);
}
return tmp;
}