Boolan_c++第4周笔记

革命尚未成功,同志仍需努力

1、导读

1) 泛型编程(Generic Programming)和面向对象编程(Object-Oriented Programming)是c++的技术主线。

推荐书记:《c++ primer》第五版;《c++ programming language》《effective c++》(有中文版)《effective modern c++》《the c++ standard library》《STL源码剖析》

模版库是用模版编程的思维做出来的。

2、Conversion Function(转换函数)

class A创建的对象转换成别的类型,或者将别的类型转为class A类型

class Fraction

{

public:

    Fraction(int num, int den = 1)

        :m_numerator(num), m_denominator(den) {   }

    operator double() const {      

//operator double() 想将这个类转换成double类型,double里面不可有参数,没有返回类型,转换不应有改变,通常加const

        return (double)(m_numerator / m_denominator);

}

private:

    int m_numerator;

    int m_denominator;

};

Fraction f(3,5);

double d = 4+f;   //调用operator double()将f转为0.6

3、non-explicit-one-argument ctor 不是explicit类型 一个参数有默认值,只需要给一个参数赋值即可(可以把别的东西转换成这种)

1)

class Fraction

{

public:

    Fraction(int num, int den = 1)

        : m_numerator(num), m_denominator(den) { }

    Fraction operator+(const Fraction& f)

        return Fraction(......);

private:

    int m_numerator;

    inr m_denominator;

}

Fraction f(3,5);

Fraction d2 = f+4;  //调用non-explicit ctor 将4转为Fraction(4,1),然后调用operator+

Fraction f(3,5); Fraction d2=f+4;//会报错,要根据使用判断函数,使用f+4上述代码中黄绿不可并存,

2)explicit-one-argument ctor

(explicit明白的,明确的)告诉编译器不要随便给我做事情,用到构造函数再调用,不可以把3变成3/1

class Fraction

{

    explict Fraction(int num, int den=1)

        :m_numerator(num), m_denominator(den) {  }

    operator double() const{

        return (double) (m_numerator / m_denominator);}

    Fraction operator+(const Fraction& f) {  //这里定义的加法,左右两边都应该是Fraction

        return Fraction(......);

}

private:

    int m_numerator;

    int m_denominator;

};

Fraction f(3,5);

Fraction d2=f+4;  //[Error] 4无法变成Fraction类型

explict大多数情况下都用在构造函数前面。

template    // templete

class vector<bool, Alloc>    //模版的偏特化,vector中存放的每一个值是bool类型

{

public:

    typedef  __bit_reference reference;

protected:

    reference operator[ ] (size_type n)   //对[ ]做重载,传回值是reference,应该传回bool值,但是现在传回的是reference,需要一个转换函数将其转换为bool值

        {return *(begin() + difference_type(n));}

...

}

struct  __bit_reference   

{

    unsigned int* p;

    unsigned int mask;

public:

    operator bool() const { return !(!(*p & mask));}  //转换函数,将reference值转换成bool值

...

4)pointer-like classes

<1>关于智能指针(比指针功能更多)

class对象像指针或者像函数

智能指针里面一定带有一个真正的指针,有* 和 -> 两种操作

左边大圈圈像指针,里面有个真正的指针px

templete

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;

}

<2> 关于迭代器

代表容器中一个元素,遍历容器

5、function-like classes,仿函数

如果class里面有 operator( )  则是仿函数

6、namespace  //不同团队开发代码,把自己团队的都放到一个namespace下,防止和别人重名

namespace jj01

{ }

namespace jj02

{ }

测试:

int main(int argc, char** argv)

{

    jj01::test_member_template();

    jj02::test_template_template_param();

}


c++模板

模板是实现代码重用机制的一种工具,可以实现类型参数化,把类型定义为参数,从而实现代码可重用

模板分类:函数模版和类模版,成员模版。函数模版针对参数类型不同的函数;类模版仅针对数据成员和成员函数类型不同的类

注意:模版的声明或定义只能在全局,命名空间或类范围内进行。不能在局部范围,函数内进行,如不可在main()函数中声明或定义一个模版。


7、class template,类模板

设计一个类其某些变量可以被用户任意改变

8、Function Template,函数模板

函数模板使用时不用写类型

//学过c的童鞋们一定都写过函数sum吧,当时是这样写的:

int sum(int a,int b){ return a+b;}//实现了整数的相加

//如果再想同时实现小数的相加,就再多写个小数的相加。普通实现我就不写了,知道函数重载的童鞋们会这样写:

int sum(int a, int b){

//第一个function 

 return a+b;}

double sum(double a,double b){

//第二个function 

 return a+b;}

//这样我们就可以只用一个sum函数 就可以实现整数相加与小数相加。

//但是这样我们还是要定义两个函数。

//C++考虑了怎么避免这种重复的操作,代码如下: 函数模板的声明。

templete

T sum(T a, T b)

{return a+b;}

//只需要定义一个函数与只使用一个函数实现两数相加。

9、member template,成员模板

标黄部分定义了一个模版,该模版是在模版内部,称为成员模版;T1,T2允许变化,U1,U2也可以变化

语法:

template

    template

反之是不可以的

template

class shared_ptr:public __shared_ptr<_Tp>

{

...

    template

    explicit shared_ptr(_Tp1* __p)

            :__shared_ptr<_Tp>(__p) { }

...

};

Base1* ptr = new Derived1;

shared_ptrsptr(new Derived1);


10、模版特化(某些独特的类型要做特殊设计,将模版局部的特征化)

模版泛化,有一个类型,用时指定

template

struct hash {  };  //泛化


template<>  //  以下为特化。Key被绑定,所以不在这里显示

struct hash

{

//如果用户指定类型是char,int,long,可以用以下代码

    size_t operator () (char x) const {return x;}  //对()做重载

};

template<>

struct hash

{

    size_t operator() (int x) const { return x; }

};

template<>

struct hash

{

    size_t operator() (long x) const { return x; } 

};

使用  cout << hash () (1000); 会去找有对应的特化,则用特化,1000的()是重载,1000是long x。


11、模版偏特化(局部特化)

1)个数的偏

模版中有多个模版参数,此例中有两个,要绑定其中一个(绑定要依次从左到右)。

T被绑定到bool上,Alloc不确定也要写下来

2)范围的偏

任意类型 变成指针指向的类型

templete

class C

{ ... };   //先写一个任意类型的 

templete

class C   //当用户是指针类型的要用这个(偏特化)

{ ... };

根据用户不同的调用形式是否有指针,来调用不同段的代码


12、模版模版参数

templatetemplate class Container> //模版模版参数

class XCls

{

private:

    Container c;

public:

    ......

};


13、c++标准库

标准库提供给我们:数据结构,容器,算法

标准库给出的要直接用 不需要自己写

编译器  Dev c++ 支持c++11。project     、Project Option

14、三个主题(c++11)

1)数量不定的模版参数

void print()  //最后剩零个参数调用此函数

{

}

template  //参数很多个,把参数分为一个和一个包(...)

void print(const T& firdtArg, const Type&...args)

{

    cout << firstArg << endl;

    print(args...);   //先打印7.5,然后再调用print将剩下的参数分为一个和一包,再进行递归。

}

调用:print(7.5, "hello", bitset<16>(377),42);

%%一个和一包(pack)里面所做的操作任意

求一包里面参数个数:sizeof...(args)     //要加...

2)auto(since c++11)

以前版本:

list c;

...

list::iterator ite;

ite = find(c.begin(),c.end(),target);

c++11:

list c;

...

auto ite = find(c.begin(), c.end(), target);  编译器通过等号右边自动推出左边auto是什么

//下面写法是错误的

list c;

...

auto ite;  //这里❌  编译器无法推测auto类型

ite = find(c.begin(), c.end(), target);

3)ranged-base for

for(decl : coll) //decl是变量,coll是容器,将容器中值赋给左边变量,再进行下面计算

{ statement }

for(int i: {2,3,5,7,9,13,17,19})  //在c++11中容器可以直接用大括号列出来

{cout << i << endl;}

elem等同于容器中元素,类型不想写了用auto。*3之后不影响原来的值(用传值非方式)

for(auto& elem: vec) {elem *= 3;} 传引用,改变原来值。//引用就是指针

你可能感兴趣的:(Boolan_c++第4周笔记)