C++ 设计

目录

RAII(Resource Acquisition Is Initialization)

ScopeGuard

NVI(Non-Virtual Interface)

CRTP(Curiously Recurring Template Pattern)

PIMPL(Private Implementation)

SFINAE(Substitution Failure Is Not An Error)

Mixin


RAII(Resource Acquisition Is Initialization)

即资源获取就是初始化,是一种管理资源的机制。

如管理new操作符的资源:

class A
{
public:
	int *p;

	A(int n)
	{
		p = new int[n];
	}
	~A()
	{
		delete p;
	}
};

int main()
{
	A a(10);
	// a.p
	return 0;
}

只写了一个简单的示例。

一个经典的案例:lock_guard类,源代码如下

		// CLASS TEMPLATE lock_guard
template<class _Mutex>
	class lock_guard
	{	// class with destructor that unlocks a mutex
public:
	using mutex_type = _Mutex;

	explicit lock_guard(_Mutex& _Mtx)
		: _MyMutex(_Mtx)
		{	// construct and lock
		_MyMutex.lock();
		}

	lock_guard(_Mutex& _Mtx, adopt_lock_t)
		: _MyMutex(_Mtx)
		{	// construct but don't lock
		}

	~lock_guard() noexcept
		{	// unlock
		_MyMutex.unlock();
		}

	lock_guard(const lock_guard&) = delete;
	lock_guard& operator=(const lock_guard&) = delete;
private:
	_Mutex& _MyMutex;
	};

实例化的时候加锁,生命周期结束的时候自动解锁。

ScopeGuard

这个方法是定义一个ScopeGuard模板类,用于管理临时使用的资源。

把临时资源的释放操作写成lambda表达式,申请ScopeGuard实例存放这个表达式,实例生命周期结束时自动执行。

代码:

template <typename Lambda>
class ScopeGuard
{
public:
	ScopeGuard(Lambda &&lam): lambda (lam) {
	}
	~ScopeGuard() {
		lambda();
	}
private:
	Lambda lambda;
};

template <typename T>
ScopeGuard<T> GetScopeGuard(T &&lambda)
{
	return ScopeGuard<T>(move(lambda));
}

int main()
{
	int* p = new int[100];
	GetScopeGuard([&] {delete[] p; });
	return 0;
}

NVI(Non-Virtual Interface)

NVI是用非虚函数调用虚函数,把非虚函数作为接口。

class A
{
public:
	void show()
	{
		cout << "A\n";
		print();
	}
	virtual void print() {};
};
class B :public A
{
public:
	void print()
	{
		cout << "x=" << x;
	}
private:
	int x;
};

int main()
{
	B b;
	b.show();
	return 0;
}

CRTP(Curiously Recurring Template Pattern)

奇异的递归模板模式,指的是子类继承一个模板类,模板的特化类型是子类本身。

最简代码:

#include<iostream>
using namespace std;

template<typename T>
class Base
{
public:
    void virtualFunc()
    {
        static_cast<T*>(this)->realFunc();
    }
};

class Chird :public Base<Chird>
{
public:
    void realFunc()
    {
        cout << "real func";
    }
};

int main() 
{
    Chird().virtualFunc();
    return 0;
}

这个简单的例子就能看出CRTP的写法,也能看出,其实本质上静态多态。

CRTP的好处是,静态多态比继承虚函数的动态多态要快。

应用:

CRTP单例模板

CRTP + 模板方法模式

PIMPL(Private Implementation)

通过一个私有的成员指针,将指针所指向的类的内部实现全部隐藏。

普通代码:

class A
{
public:
	int f(int n)
	{
		return f1(n) + n + f2(n);
	}
private:
	int f1(int n)
	{
		return n * n * n;
	}
	int f2(int n)
	{
		return n > 0 ? 1 : -1;
	}
};

PIMPL代码:

class B;
class A
{
public:
	A()
	{
		opt = new B();
	}
	int f(int n)
	{
		return opt->f1(n) + n + opt->f2(n);
	}
private:
	B* opt;
};

class B 
{
public:
	int f1(int n)
	{
		return n * n * n;
	}
	int f2(int n)
	{
		return n > 0 ? 1 : -1;
	}
};

SFINAE(Substitution Failure Is Not An Error)

SFINAE是指泛型函数在编译的时候,会尝试生成所有实例,如果生成失败也不会报错,直到最后确定重载版本的时候如果没有正确版本才会报错。

template <typename T>
void print(T x)
{
	cout << x;
}
void print(vector<int>x)
{
	cout << x[0];
}

int main()
{
	vector<int>x = { 1,2,3 };
	print(x);
	return 0;
}

在这个例子中,泛型函数print首先会生成实例,但是里面会编译失败,继续编译,普通函数print可以满足条件,最终选用它而忽略泛型实例。

应用:通过重载版本判断一个参数类型是不是类

class A
{
	//
};

class IsClass
{
public:
	template<typename C> static char f(int C::*);
	template<typename C> static int f(...);
};

int main()
{
	bool flag1 = sizeof(IsClass::f<A>(0)) == 1; // true
	bool flag2 = sizeof(IsClass::f<int>(0)) == 1; // false
	return 0;
}

Mixin

Mixin就是模板类继承模板参数类。

代码:

template<class B>
class A:public B
{
public:
    void print()
    {
        cout << "the name is ";
        B::print();
    }
};
class B
{
public:
    void print()
    {
        cout << "B";
    }
};

int main()
{
    A<B> a;
    a.print();
    return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值