- 本文介绍了 C++ 的 5 个特别用法(Idioms),分别是
- Curiously Recurring Template Pattern;
- Empty Base Optimization;
- Erase-Remove;
- Inner Class;
- Int to Type;
11. Curiously Recurring Template Pattern
用途
- 使用派生类作为模板参数特化基类模板
- 静态多态
- 对象计数器
示例代码
静态多态
template <typename D>
class Base
{
public:
void interface() {
cout << "void Base::interface(), begin..." << endl;
static_cast<D*>(this)->implementation();
cout << "void Base::interface(), end..." << endl;
}
static void static_interface() {
cout << "static void Base::static_interface(), begin..." << endl;
D::static_implementation();
cout << "static void Base::static_interface(), end..." << endl;
}
void implementation() {
cout << "void Base::implementation(), begin..." << endl;
cout << "void Base::implementation(), end..." << endl;
}
static void static_implementation() {
cout << "static void Base::static_implementation(), begin..." << endl;
cout << "static void Base::static_implementation(), end..." << endl;
}
};
class Derived : public Base<Derived>
{
public:
static void static_implementation() {
cout << "static void Derived::static_implementation(), begin..." << endl;
cout << "static void Derived::static_implementation(), end..." << endl;
}
void implementation() {
cout << "void Derived::implementation(), begin..." << endl;
cout << "void Derived::implementation(), end..." << endl;
}
};
int main() {
Derived::static_implementation();
Derived::static_interface();
Base<Derived>::static_implementation();
Base<Derived>::static_interface();
Base<Derived> bd;
bd.implementation();
bd.interface();
bd.static_implementation();
bd.static_interface();
return 0;
}
对象计数器
template <typename T>
class Counter
{
public:
static size_t objects_created;
static size_t objects_alive;
public:
Counter() { ++objects_created; ++objects_alive; }
Counter(const Counter& c) { ++objects_created; ++objects_alive; }
protected:
~Counter() { --objects_alive; }
};
template <typename T>
size_t Counter<T>::objects_created;
template <typename T>
size_t Counter<T>::objects_alive;
class Point : public Counter<Point>
{
public:
Point() : x(0.0), y(0.0), z(0.0) {}
Point(double xx, double yy, double zz) : x(xx), y(yy), z(zz) {}
Point(const Point& p) : x(p.x), y(p.y), z(p.z) {}
private:
double x, y, z;
};
void count_point() {
cout << "There are " << Counter<Point>::objects_created << " points created." << endl;
cout << "There are " << Counter<Point>::objects_alive << " points still alive." << endl;
}
int main() {
Point p1;
count_point();
Point p2, p3 = p1;
count_point();
{
Point p4;
count_point();
Point p5;
}
count_point();
return 0;
}
12. Empty Base Optimization
用途
- 空类的对象的大小不能为 0,否则如下代码所示数组将无法正常工作
class Empty {};
Empty arr[10];
Empty* p = arr + 1;
- 但是当空类对象是另一个类的数据成员时,却因为字节对齐造成空间浪费
- C++ 的做法是
- 空类的大小为 1
- 如果一个类继承自空类,则该类不会将这 1 个字节包含在内
- 如果一个类有空类对象成员,还是会保留这个字节,并执行对齐
示例代码
class E1 {};
class E2 {};
template <class Base1, class Base2, class Member>
struct BaseOptimization
{
Member member;
BaseOptimization() {}
BaseOptimization(const Base1& b1, const Base2& b2, const Member& mem)
: Base1(b1), Base2(b2), member(mem) {}
};
class Foo
{
BaseOptimization<E1, E2, int> data;
};
int main() {
cout << "size of BaseOptimization: " << sizeof(BaseOptimization<E1, E2, int>) << endl;
cout << "size of Foo: " << sizeof(Foo) << endl;
return 0;
}
13. Erase-Remove
用途
示例代码
template <typename T>
inline void remove_all_items(std::vector<T>& v, const T& item) {
v.erase(std::remove(v.begin(), v.end(), item), v.end());
}
template <typename C>
inline void print_container(const C& c) {
for (auto it = c.begin(); it != c.end(); ++it)
cout << *it << " ";
cout << endl;
}
int main() {
vector<int> int_vec{0, 1, 1, 2, 4, 6, 6, 8};
print_container(int_vec);
cout << int_vec.size() << endl;
remove_all_items(int_vec, 6);
print_container(int_vec);
cout << int_vec.size() << endl;
return 0;
}
14. Inner Class
用途
- 在不使用多重继承的情况下实现多组接口
- 在一个抽象内提供一个接口的多种实现
示例代码
class Base1
{
public:
virtual void func() = 0;
~Base1() {}
};
class Base2
{
public:
virtual void func() = 0;
~Base2() {}
};
class Derived
{
friend class Base1Impl;
friend class Base2Impl;
private:
class Base1Impl : public Base1
{
public:
Base1Impl(Derived* pd) : parent(pd) {}
void func() override { return parent->base1_func(); }
private:
Derived* parent;
} base1_obj;
class Base2Impl : public Base2
{
public:
Base2Impl(Derived* pd) : parent(pd) {}
void func() override { return parent->base2_func(); }
private:
Derived* parent;
} base2_obj;
void base1_func() { cout << "Derived::base1_func()" << endl; }
void base2_func() { cout << "Derived::base2_func()" << endl; }
public:
Derived() : base1_obj(this), base2_obj(this) {}
operator Base1&() { return base1_obj; }
operator Base2&() { return base2_obj; }
};
void base1_func(Base1& b1) { return b1.func(); }
void base2_func(Base2& b2) { return b2.func(); }
int main() {
Derived d;
base1_func(d);
base2_func(d);
return 0;
}
15. Int to Type
用途
- 一个整数代表一个不同的类
- 函数重载:根据不同的整数调用不同的函数
示例代码
template <int I>
struct Int2Type
{
enum {value = I};
using value_type = int;
using type = Int2Type<I>;
using next = Int2Type<I + 1>;
using previous = Int2Type<I - 1>;
};
template <typename T, size_t N>
class Array : public array<T, N>
{
private:
enum AlgorithmType {NOOP, INSERTION_SORT, QUICK_SORT};
static const int algo = (N == 0) ? NOOP :
(N == 1) ? NOOP :
(N < 50) ? INSERTION_SORT : QUICK_SORT;
void sort(Int2Type<NOOP>) { cout << "sort: NOOP" << endl; }
void sort(Int2Type<INSERTION_SORT>) { cout << "sort: INSERTION_SORT" << endl; }
void sort(Int2Type<QUICK_SORT>) { cout << "sort: QUICK_SORT" << endl; }
public:
void sort() { sort(Int2Type<algo>()); }
};
int main() {
Array<int, 1> arr1;
arr1.sort();
Array<int, 10> arr10;
arr10.sort();
Array<int, 100> arr100;
arr100.sort();
return 0;
}