函数调用操作(c++语法中的左右小括号)可以被重载,STL的特殊版本都以仿函数形式呈现。如果对某个class进行operator()重载,它就成为一个仿函数。
仿函数(functor),就是使一个类的使用看上去象一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了
#include <iostream> using namespace std; template<class T> struct Plus { T operator()(const T& x, const T& y)const { return x + y; } }; template<class T> struct Minus { T operator()(const T& x, const T& y)const { return x - y; } }; int main() { Plus<int>plusobj; Minus<int>minusobj; cout << plusobj(3, 4) << endl; cout << minusobj(3, 4) << endl; //以下直接产生仿函数的临时对象,并调用 cout << Plus<int>()(43, 50) << endl; cout << Minus<int>()(43, 50) << endl; system("pause"); return 0; }
产生临时对象的方法:在类型名称后直接加一对小括号,并可指定初值
vector<int>() = {1};
。stl常将此技巧应用于仿函数与算法的搭配上。
#include <iostream> #include <vector> #include <algorithm> using namespace std; /* template <class InputIterator,class Function> Function for_each(InputIterator first, InputIterator last, Function f) { for (; first != last; ++first) { f(*first); } return f; } */ template <typename T> class print { public: void operator()(const T& elem) { cout << elem << ' ' << endl; } }; int main() { int ia[6] = { 0,1,2,3,4,5 }; vector<int>iv(ia, ia + 6); for_each(iv.begin(), iv.end(), print<int>()); system("pause"); return 0; }
静态常量整数成员在class内部直接初始化,否则会出现链接错误。
In C++11, non-
static
data members,static constexpr
data members, andstatic const
data members of integral or enumeration type may be initialized in the class declaration. e.g.struct X { int i=5; const float f=3.12f; static const int j=42; static constexpr float g=9.5f; };
In this case, the
i
member of all instances of classX
is initialized to5
by the compiler-generated constructor, and thef
member is initialized to3.12
. Thestatic const
data memberj
is initialized to42
, and thestatic constexpr
data memberg
is initialized to9.5
.Since
float
anddouble
are not of integral or enumeration type, such members must either beconstexpr
, or non-static
in order for the initializer in the class definition to be permitted.Prior to C++11, only
static const
data members of integral or enumeration type could have initializers in the class definition.
const
和 constexpr
变量之间的主要区别在于:const
变量的初始化可以延迟到运行时,而 constexpr
变量必须在编译时进行初始化。所有 constexpr
变量均为常量,因此必须使用常量表达式初始化。
对于修饰Object来说,const并未区分出编译期常量和运行期常量,constexpr限定在了编译期常量。
编译器常量的特点就是:它的值在编译期就可以确定。比如:const int i = 5;
在运行时常量,它的值虽然在运行时初始化后不再发生变化,但问题就在于它的初始值要到编译时才能确定。比如:
srand(clock());
const int i = rand();
虽然i的值在定义并初始化成不会再发生变化(除非你使用一些不符合标准的小技巧),但再聪明的编译器也无法在编译时确定它的值。
编译期常量最常见的例子是编译时的常数定义,比如:
const double PI = 3.1415926;
运行期常量的最常见的例子是函数的常量参数(包括常引用,常指针参数)比如:
void f(const string& s) {...}
次常见的例子是类的非静态常量成员。
——这些都是一经初始化,不允许再发生变化的,但其初始值必须到运行时才能知道。
#include <iostream> #include <vector> #include <algorithm> using namespace std; template <typename T> class testClass { public: static const int a = 5; static const long b = 3L; static const char c = 'c'; static const double d = 100.1; }; int main() { cout << testClass<int>::a << endl; cout << testClass<int>::b << endl; cout << testClass<int>::c << endl; //下面的语句出错,带有类内初始值设定项的静态数据成员必须具有不可变的常量整型 cout << testClass<int>::d << endl; system("pause"); return 0; }
increment(++)实现(前置式及后置式),dereference(*)实现
i++调用operator++(int), ++i调用operator++()
#include <iostream> #include <vector> #include <algorithm> using namespace std; class INT { friend ostream& operator<<(ostream& os, const INT& i); public: INT(int i) :m_i(i) {}; //自增然后得到值 INT& operator++() { ++(this->m_i); return *this; } //先得到值然后自增 const INT operator++(int) { INT temp = *this; ++(this->m_i); return temp; } //取值 int& operator*() const { return (int&)m_i; //下面的语句会出错,因为将int&类型的引用绑定到const int类型的初始值设定项。由于函数是const成员函数导致 //return m_i; } private: int m_i; }; ostream& operator<<(ostream& os, const INT& i) { os << '[' << i.m_i << ']' << endl; return os; } int main() { INT I(5); cout << I++; cout << ++I; cout << *I; system("pause"); return 0; }