1. 程式人生 > >【學習筆記】條款35:考慮virtual函式以外的其他選擇 & bind & function模板

【學習筆記】條款35:考慮virtual函式以外的其他選擇 & bind & function模板

來源書籍:

Effective C++
C++ Primer

條款35:考慮virtual函式以外的其他選擇

Template Method

對於一個繼承體系來說,其中某一個功能可能會根據繼承不同而實現不同,可以不直接使用虛擬函式。定義一個public的non-virtual成員函式,呼叫一個private virtual函式,private virtual函式如同一般的virtual函式。這一手法稱為non-virtual interface手法,它是所謂的Template Method設計模式,這個non-virtual函式成為virtual函式的外覆器。
這樣的好處是,可以在呼叫virtual之前做一些事前工作和呼叫之後做一些事後工作。這意味著外覆器確保得以在一個virtual函式被呼叫之前設定好適當場景,並在呼叫結束之後清理場景。

Strategy && function<>

利用函式指標/function<>模板,著重放在function<>上,他可以接受一個可呼叫物件。
callable object 包括傳統C函式,C++成員函式,函式物件(實現了()運算子的類的例項),lambda表示式(特殊函式物件)

#include<iostream>
#include<functional>
class GameCharacter;

int defaultHealthCalc(const GameCharacter &c);

class
GameCharacter { typedef std::function<int(const GameCharacter&)> HealthCalcFunc; public: explicit GameCharacter(std::function<int(const GameCharacter&)>func = defaultHealthCalc) :healthfunc(func) {} int healthValue() { return healthfunc(*this); } protected: HealthCalcFunc healthfunc; }; class Level { public: Level(int n = 5):num(n){} float health(const GameCharacter &c) { std::cout << "Level Function : " << num << std::endl; return -1; } private: int num; }; class Badguy :public GameCharacter { typedef std::function<int(const GameCharacter&)> HealthCalcFunc; public: explicit Badguy(std::function<int(const GameCharacter&)>func = defaultHealthCalc){ healthfunc = func; } }; int defaultHealthCalc(const GameCharacter &c) { std::cout << "Default Function" << std::endl; return -1; } int main() { GameCharacter a; a.healthValue(); GameCharacter b([](const GameCharacter &b) {std::cout << "lambda" << std::endl; return -1; }); b.healthValue(); Level currentlevel(5); Badguy c(std::bind(&Level::health, currentlevel, std::placeholders::_1)); c.healthValue(); getchar(); return 0; }

此例中展示了function<int(const GameCharacter&)>的用法,其中呼叫Level的成員函式時,用了bind綁定了物件和引數。

bind()

接受一個可呼叫物件,生成一個新的可呼叫物件來“適應”原物件的引數列表

繫結普通函式

例如:auto g = bind(f, a, b, _2, c, _1);
則呼叫g(x,y)的效果等同於呼叫f(a,b,y,c,x)
f可以是函式名也可以是函式指標

繫結成員函式

除了繫結引數列表,還可以把某個物件繫結到對應類上的成員函式上。但是成員函式隱含的需要一個*this來用,這樣實際上隱含的講該物件的*this傳遞給了該成員函式。
例如

Class A{
    int f(int a,int b){…………}
};
A obj;
auto g = bind(&f, obj, 1, _1);

這樣g(x)的效果等同為 obj.f(1,x);
注意,bind()時必須在成員函式前面加上取地址的操作符&表示這是一個成員函式指標。bind()同樣支援繫結虛成員函式。