C++学习笔记3--类

  • 转换函数
  • pointer-like class & function-like class
  • 泛型编程
  • 模板特化

转换函数

转换函数有两个方向。

##将类转换成别的类##
class Fraction
{
operator double() const
{return (double)(m_numerator/m_denominator);}
}
////////
Fraction f(3,5);
double d=4+f;

编译器行为:首先查找有没有+的重载,没有。那么尝试把f转换成double,找到有operator double(),于是把f转成double。

non-eplicit-one-argument ctor

class Fraction
{
    Fraction(int num, int den=1)
        :m_numerator(num),m_denominator(den)
    {}
    Fraction operator+(const Fraction& f)
    {return Fraction(...);}
}
////////
Fraction f(3,5);
double d2=f+4;

编译器行为:找fraction有没有+的重载,找到了,但是这个函数的参数是个fraction,不是double,于是编译器看能否把4转换成fraction,于是调用上面的non-explicit-one-argument ctor,把4转换成4/1。

explicit

class Fraction
{

    explicit 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)
    {return Fraction(...);}
}

如果ctor和转换函数并存,对于d2=f+4来说,既可以把f再转换成double,又可以把4转成fraction,产生ambiguous歧义。但是对于d=4+f来说可以并存的。

解决办法:在Fraction ctor前面加上explicit。这样4就不会自动转换成fraction。此时[error] conversion from double to fraction requested.

问题:f+4不调用double转换吗?

标准库中的应用:

operator[]重载这个函数应该返回一个bool值,但是却返回了reference,这是一个__bit_reference类,代码中包括了operator bool() const这样的一个转换函数。

pointer-like classes#

智能指针#

有时候会将类构造成一个指针,这个类具有和指针同样的操作,但是比指针要更智能一些。

struct Foo
{
    void method(void){...}
};

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

首先创建一个智能指针sp,初始化用new Foo的普通指针。
然后来看 * 这个操作,是取一个对象,那么函数应该返回 *px。
对于->这个操作,通过指针调用函数method,函数应该返回px, 等同于px->method(); 但是当->作用上去,这个->符号被消耗掉了,那么px怎么调用method呢?这里的解释是->这个符号是连续作用的。

迭代器

迭代器要指向容器中的一个元素,所以也是一个point-like class。但是迭代器由于有遍历操作,所以还要实现++,–等操作。

reference operator*() const
{return (*node).data;}
pointer operator->() const
{return &(operator*() );}

///////////////////////////////
list<Foo>::iteration it;
*it;
it->method();

对于*,取得的是一个object。

对于->,意思是调用Foo::method();相当于(*it).method();
相当于(&(*it))->method();

function-like classes

主要是对于()的重载。因为函数主要通过()对函数调用。

C++里面有个类叫pair,第一个元素和第二个元素可以是任意类。现在我们要设计function-like classes,来取它的第一个和第二个元素值。

类里面没有成员函数吗?为什么要用一个类来模拟呢?

对于select1st这个类来说,接收的是Pair类型的class,对()重载返回第一个元素。灰色的地方还有继承关系,这里没有写出来。

调用形式:select1st<pair>()();

第一个小括号创建临时对象,第二个调用operator()重载。

namespace

可以利用不同的namespace进行测试。

template

class template

template<typename T>

对数据类型进行操作,每创造不同类型的对象,就会创造出一份代码。所以也有人说模板会引起代码的膨胀。

function template

templete<class T>
inline
const T& min(const T&a, const T&b)
{
    return b < a ? b : a;
}

当对一个类进行比大小的时候,发现对所有的类都是一样的操作,所以把类型变成一个类。
但是在使用的时候不用像类模板一样指明类型,编译器会进行自动推导。
当调用r3=min (r1,r2)的时候,b < a, 但是编译器并不知道怎么比较大小,所以去找b有没有对<的运算符重载。所以还应该在类里对<进行运算符重载。

member template

template <class T1, class T2>
struct pair{
T1 first;
T2 second;
pair(): first(T1()),second(T2()){}
pair(const T1& a, const T2& b):first(a),second(b) {}
template <class U1,class U2>
pair(const pair<U1, U2>&p):
    first(p.first),second(p.second){}
};

//////////////////////////////////////
pair<Derived1,Derived2> p;
pair<Base1,Base2> p2(p);

成员模板允许上述对p2初始化的动作。假设有四个类,父类分别是鱼类和鸟类,各自的派生类是鲫鱼和麻雀。那么我们可以把鲫鱼和麻雀组成的pair放入一个由鱼类和鸟类构成的pair中。因为此时赋值操作first(p.first)能够成功,因为鲫鱼是一种鱼类,反之不可。

标准库应用:
对于普通指针有如下用法:

Base1* p=new Derived1;//up-cast

对于上面出现过的智能指针也应该有这个功能

template<typename _Tp>
class shared_ptr:public__shared_ptr<_Tp>
{
    template<typename _Tp1>
    explicit shared_ptr(_Tp1* __p)
        :__shared_ptr<_Tp>(__p){}
}
//////////////////////////////////
shared_ptr<Base1> sptr(new Derived1);

specialization 模板特化

针对模板的特殊类型进行的设计。比如原来template能够传很多类型,但是你现在针对一个bool类进行设计。被绑定之后不用写尖括号里面的东西。

偏特化-个数的偏

原来有两个参数,现在绑定一个。

偏特化-范围

原来的类型是T,现在只是指定指针。

class <typename T>
class C {};

class <typename T>
class C<T*>{};

模板模板参数

模板的第二个参数也是个模板,Container以第一个模板参数作为参数。用户在使用的时候XCLs<string, list> mylist;指定任意类型和任意容器。但是容器的模板还有第二第三参数,所以直接写<string,list>编译器无法通过,需要用using...这句话。

对于容器之外的参数,比如SmartPtr接收一个参数的就可以直接通过。

对于下面这种情况,第二个参数是被制定好的,这不是模板模板参数。