C++ 学习4 泛型编程 面向对象

来源:互联网 发布:手机淘宝怎么清理缓存 编辑:程序博客网 时间:2024/04/30 22:35
  • Conversion function
  • non-explicit one argument ctor
  • Pointer liker classes 智能指针,迭代器
  • Function like classes Functor 仿函数
  • namespace
  • class template function template
  • specialization, Partial spectialization
  • template template parameter 模板模板参数
  • STL
  • C++11 :Varadic template, auto, ranged-base for
  • 引用 refernce
  • 复合&继承关系下的构造与析构

Conversion function 转换函数

class Fraction{public:    Fraction(int num, int den=1):m_num(num), m_den(den) { }    operator double() const {    return (double) m_num/m_den ;}private:    int m_num, m_den;};Fraction f(3,4);double d = 4 + f;//调用operator double() 将f转换为double。

此处不写return type 由于已经指定double;
全局函数operator + (left + right) <–> left + right

non-explicit-one-argument ctor

class Fraction{public:        Fraction (int num, int den = 1): m_num(num), m_den(den) { }Fraction operator+ (const Fraction& f) {    return Fraction (...);}   private:    int m_num, m_den;};Fraction f(3, 5);Fraction d2 = f + 4;//调用non-explicit ctor 将4转为Fraction(4,1)然后调用operator +

注意此处与conversion function区别 如果定义d2 为double 类型与上面相同则无法转换。
注意 operator + (单参数) <–> f + 4;
左 + 右
无法 调用 4 + f;

如果同时定义转换函数和单参数non-explicit 构造函数将会造成错误编译器无法选择。
如果构造函数前面加上explicit 关键字 构造函数无法自动转化4 为 Fraction 类型 此处也会产生错误。
STL中conversion函数的应用

template <class Alloc>class vector<bool,Alloc>{public:typedef __bit_reference refernce;protected:refernce operator[](size_type n) {    return *(begin() + difference_type(n));}}...struct __bit_refernce {    unsigned int*p;    unsigned int mask;public:    operator bool() const {    return !(!(*p & mask));}} 

此处reference 可以自动转换为bool 类型 。

Pointer-like classes

1.智能指针

template<class T>class shared_ptr{public:    T& operator*() const    {return *px;}    T* operator->() const    {return px;}    shared_ptr(T* p):px(p) {}private:    T* px;    long* pn;...};struct Foo{    method() {}};shared_ptr<Foo> sp(new Foo);Foo f(*sp);sp->method(); --> px->method

即必须重载 类内操作符 operator * 和operator-> 注意此处-> 符号并不会消耗。
STL boost
unique_ptr scoped_ptr 独占指针对象,并保证指针所指对象生命周期与其一致
shared_ptr shared_ptr 可共享指针对象,可以赋值给shared_ptr或weak_ptr。
指针所指对象在所有的相关联的shared_ptr生命周期结束时结束,是强引用。
weak_ptr weak_ptr 它不能决定所指对象的生命周期,引用所指对象时,需要lock()成shared_ptr才能使用。
参考:http://blog.csdn.net/xt_xiaotian/article/details/5714477
https://my.oschina.net/hevakelcj/blog/465978
2. 迭代器

template<class T>struct __list_node {    void* prev;    void* next;    T data;};template<class T, class Ref, class Ptr>struct __list_iterator {    typedef __list_iterator <T, Ref, Ptr> self;    typedef Ptr Pointer;    typedef Ref refernce;    typedef __list_node<T>* link_type;    link_type node;    bool operator==(const self& x) const {return node == x.node;}    bool operator != (const self& x) const {return node !=x.node;}    refernce operator*() const {return (*node).data;}    pointer operator->() const {return &(operator*());}    self& operator++() {node = (link_type) (*node).next;return *this;}    self& operator++(int) {self tmp = *this; ++*this;return tmp;}self& operator--() {node = (link_type)((*node).prev); return *this;}self operator--() {self tmp = *this;--*this; return tmp;}}
    (1)前置++运算符的重载方式:    成员函数的重载: 函数类型& operator++()    友元函数的重载:friend 函数类型& operator++(类类型& )    (2)后置++运算符的重载方式:    成员函数的重载:函数类型& operator++(int)    友元函数的重载:friend 函数类型& operator++(类类型&, int)

1、输入迭代器:只读,一次传递
为输入迭代器预定义实现只有istream_iterator和istreambuf_iterator,用于从一个输入流istream中读取。一个输入迭代器仅能对它所选择的每个元素进行一次解析,它们只能向前移动。一个专门的构造函数定义了超越末尾的值。总是,输入迭代器可以对读操作的结果进行解析(对每个值仅解析一次),然后向前移动。
2、输出迭代器:只写,一次传递
这是对输入迭代器的补充,不过是写操作而不是读操作。为输出迭代器的预定义实现只有ostream_iterator和ostreambuf_iterator,用于向一个输出流ostream写数据,还有一个一般较少使用的raw_storage_iterator。他们只能对每个写出的值进行一次解析,并且只能向前移动。对于输出迭代器来说,没有使用超越末尾的值来结束的概念。总之,输出迭代器可以对写操作的值进行解析(对每一个值仅解析一次),然后向前移动。
3、前向迭代器:多次读/写
前向迭代器包含了输入和输出迭代器两者的功能,加上还可以多次解析一个迭代器指定的位置,因此可以对一个值进行多次读/写。顾名思义,前向迭代器只能向前移动。没有为前向迭代器预定义迭代器。
4、双向迭代器:operator–
双向迭代器具有前向迭代器的全部功能。另外它还可以利用自减操作符operator–向后一次移动一个位置。由list容器中返回的迭代器都是双向的。
5、随机访问迭代器:类似于一个指针
随机访问迭代器具有双向迭代器的所有功能,再加上一个指针所有的功能(一个指针就是一个随机访问迭代器),除了没有一种“空(null)”迭代器和空指针对应。基本上可以这样说,一个随机访问迭代器就像一个指针那样可以进行任何操作,包括使用操作符operator[]进行索引,加某个数值到一个指针就可以向前或者向后移动若干个位置,或者使用比较运算符在迭代器之间进行比较。
参考:http://www.tuicool.com/articles/ZJ36Rf
http://blog.csdn.net/shawvichan/article/details/17639763
http://www.cnblogs.com/yc_sunniwell/archive/2010/06/25/1764934.html

Function-like classes

仿函数 functor

template <class T>struct identity {const T&operator()(const T& x) const {return x;}};template<class Pair>struct select1st {const typename Pair::first_type&operator() (const Pair& x) const {return x.first}};template <class Pair>struct select2nd {const typename Pair::second_type& operator()(const Pair& x) const {return x.second; }};template <class Arg,class Result>struct unary_function {typedef Arg argument_type;typedef Result result_type;};template <class Arg1, classArg2, class result>struct binary_function {    typedef Arg1 first_argument_type;    typedef Arg2 second_argument_type;    typedef Result result_type;};

重载operator() 实现类似函数调用方式。参考python。

参考:http://blog.csdn.net/cracker_zhou/article/details/51627811
http://blog.csdn.net/tianshuai1111/article/details/7687983
http://blog.csdn.net/Robin__Chou/article/details/49329985

namespace

#include <iostream>#include <memory>//shared_ptrusing namespace std;namespace jj01{void test_member_template(){}}//namespace//-------------#include <iostream>#include <list>namespace jj02{template<typename T>using Lst = list<T, alloctor<T>>void test_template_param(){...}}//namespace//-------------int main(int argc,char** argv){jj01::test_memeber();jj02::test_template_param();}

class template, function template, member template

1.class template

template<tyoename T>class complex{public:    complex (T r = 0, T i = 0): re (r), im(i) {}    complex& operator+= (const complex&);    T real() const {return re;}    T imag() const {return im;}private:    T re,im;    };{    complex<double> c1(1.5, 2.5);    compex<int> c2(2, 6);}
  1. function template
template<class T>inline const T&min (const T& a, const T& b) {    return b<a?b:a;}class stone{public:    stone(int w, int h, int we): _w(w), _h(h), _we(we) {}    bool operator < (const stone& rhs) const {return _we < rhs._we;}private:    int _w, _h, _we;};stone r1(2,3), r2(2,3),r3;r3 = min(r1, r2);

此处编译器会对函数模板进行推导 推导的结果是T类型为stone 调用stone:: operator <.
3. member template 成员模板

template <class T1, class T2>struct pair {    typedef T1 first_type;    typedef T2 second_type;    T1 first;    T2 second;    pair():fist(T1()), second(T2()) {}    pair(const T1& a, const T2& b): fist(a), second(b) {}    template<class U1, clas U2>    pair(const pair<U1, U2>& p):first(p.first), second(p.second) {}}//可以用于继承类中class Base1{};class Derived1:public Base1 {};class Base2{};clss Dedived2:publlic Base2 {};pair<Derived1,Deived2> p;pair<Base1, Base2> p2(p);pair<Base1, Base2> p2(pair<Derived1, Derived2>());//Derived1是Base1, Derived2是Base2,所以可以。//example 2template <typename _Tp>class shred_ptr:public __shared_ptr<_Tp>{...    template<typename _Tp1>    explicit shared_ptr(_Tp1* __p):__shared_ptr<_Tp>(__p){}};Base1* ptr = new Derived1;//up-castshared_ptr<Base1> sptr(new Derived);//模拟up-cast

如果要在外面定义成员模板,必须包含两个模板形参表,类模板形参和自己的模板形参。首先是类模板形参表,然后是自己的模板形参表。
类似:
template<class T, class Alloc> template <class I>
void MyVector<T, Alloc>::assign(I first, I last)
{
cout<<"assign"<<endl;
}

参考:http://blog.csdn.net/wuzhekai1985/article/details/6654034

specialization, 模板特化

template <class Key>struct hash {};template<>struct hash<char> {    size_t operator()(char x) const {return x;}};template<>struct hash<int> {    size_t operator()(int x) const {return x;}};template <>struct hash<long> {    size_t operator()(long x) const {return x;}};
  1. patial specialization, 模板偏特化 – 个数偏
template <typename T, typename Alloc = ...>class vector{...};template<typename Alloc = ...>class vector<bool, Alloc>{...};//bool 绑定 T
  1. 范围偏
template <typename T>class C{...};template <typename T>classC<T*>{...};c<string> obj1;c<string*> obj2;

函数没有偏特化只有全特化。
参考:
http://www.jb51.net/article/56004.htm
http://blog.csdn.net/thefutureisour/article/details/7964682/
http://blog.csdn.net/gatieme/article/details/50953564

template template parameter 模板模板参数

template <typename T, template <typename T> class Container>calss XCls{private:    Container<T> c;public:...};template <typename T>using Lst = list<allocator<T>>;XCls<string, list> mylst1;//wrongXCls<string, Lst> mylst2;//correct//----------template <typename T, template <typename T> class SmartPtr>class XCls{private:    SmartPtr<T> sp;public:    XCls(): sp(new T) {}}XCls<string, shared_ptr> p1;XCls<double, unique_ptr> p2;//wrongXCls<int, weak_ptr> p3;//wrongXCls<long, auto_ptr> p4;//----以下不是template template parametertemplate <class T, class Sequnce = deque<T>>class stack {    friend bool operator == <> (const stack&, const stack&);    friend bool operatir < <> (const stack&, const stack&);protected:    Sequence c;//底层容器};stack<int> s1;stack<int, list<int>> s2;

模板模板参数就是将一个模板作为另一个模板的参数。 所以最后一个例子不是。
另外还有无类型模板 :

template<typename T,const T EMPTY> class Grid  {...}Greid <int, 10> my grid;

指针和引用模板参数必须指向所有翻译单元中都可用的全局变量。对于这些类型的变量,相应的技术术语就是带有外部连接的数据。
使用extern声明即可。
如:

template<typename T ,const T& EMPTY>  class Grid  {...};  extern const int emptyInt=0;  Grid<int,emptyInt> myIntGrid; 

对于初始化我们还可以使用“零初始化”即 T().
无类型参数仅限于int、enmu、指针和引用
当为
参考:http://blog.csdn.net/pcliuguangtao/article/details/6449804

STL

容器,迭代器, 算法, 仿函数,待补充。

C++ 11 补充

  1. Variadic template 数量不定模板参数
void print (){}template <typename T, typename... Types>void print (const T& firstArg, const Types&...args){    cout << firstArg<<endl;    print(args...)}

此处用于tempalte paramters 就是template parameters pack (模板参数包) 个数可以用sizeof…(args) 来获得。最后sizeof…(args) = 0 时调用第一个重载的空print函数什么都不做返回。

参考:http://www.cnblogs.com/tekkaman/p/3501122.html
http://blog.csdn.net/wag2765/article/details/50581469
2. auto
C++引入auto关键字主要有两种用途:一是在变量声明时根据初始化表达式自动推断该变量的类型,二是在声明函数时作为函数返回值的占位符。

list<string> c;list<string>::iterator ite;ite= find(c.begine(),c.end9),target);//可以用auto 代替auto = find(...)//但是不能写为auto ite;ite = find(...)//此时编译器无法推断auto类型。//作为函数返回值占位符时,auto主要与decltype关键字配合使用,作为返回值类型后置时的占位符。此时,关键字不表示自动类型检测,仅仅是表示后置返回值的语法的一部分。template<class T, class U>auto add(T t, U u) -> decltype(t + u) {    return t + u;}

参考:http://blog.csdn.net/Xiejingfa/article/details/50469045
http://www.2cto.com/kf/201404/293503.html
3.Range-base for

for (decl:coll){}for (int i : {1,2,3}){    cout << i << endl;}vector<double> vec;for (auto elem :vec) {    cout << elem << endl;//按值传递}for (auto& elem: vec) {    elem* = 3;//按引用传递可以改变包内内容}

Reference引用

1.引用不能重新赋值
2. 引用不能单独声明
3. object 和其引用大小地址均相同
4. 引用不构成重载。 const 函数构成重载即func() const {} 构成重载由于其是函数签名的一部分。
5. sizeof(值) = sizeof(引用)

复合与继承关系下的构造与析构

构造由内而外
析构相反由外而内
构造先base 再component 最后自己。
Derived::Derived():Base():COmponent(){}
析构先自己再component最后base
Derived::~Derived(){…~Component,~Base()}

0 0
原创粉丝点击