模板与继承

模板与继承

命名模板参数

问题描述
解决具有默认模板的类实例化过程中,前面的模板参数还需要明确指定默认模板的问题。

解决方案

设法将缺省类型值放入到一个基类中,在根据需要通过派生类覆盖掉某些类型值,具体的代码如下:
template <typename Base, int D>
class Discriminator : public Base {
};

template <typename Setter1, typename Setter2,
          typename Setter3, typename Setter4>
class PolicySelector : public Discriminator<Setter1,1>,
                       public Discriminator<Setter2,2>,
                       public Discriminator<Setter3,3>,
                       public Discriminator<Setter4,4> {
};


// default policies

class DefaultPolicy1 {};
class DefaultPolicy2 {};
class DefaultPolicy3 {
  public:
    static void doPrint() {
        std::cout << "DefaultPolicy3::doPrint()\n";
    }
};
class DefaultPolicy4 {};


// define default policies as P1, P2, P3, P4
class DefaultPolicies {
  public:
    typedef DefaultPolicy1 P1;
    typedef DefaultPolicy2 P2;
    typedef DefaultPolicy3 P3;
    typedef DefaultPolicy4 P4;
};


// class to define a usage of the default policy values
// - avoids ambiguities if we derive from DefaultPolicies more than once
class DefaultPolicyArgs : virtual public DefaultPolicies {
};


// class templates to override the default policy values

template <typename Policy>
class Policy1_is : virtual public DefaultPolicies {
  public:
    typedef Policy P1;  // overriding typedef
};

template <typename Policy>
class Policy2_is : virtual public DefaultPolicies {
  public:
    typedef Policy P2;  // overriding typedef
};

template <typename Policy>
class Policy3_is : virtual public DefaultPolicies {
  public:
    typedef Policy P3;  // overriding typedef
};

template <typename Policy>
class Policy4_is : virtual public DefaultPolicies {
  public:
    typedef Policy P4;  // overriding typedef
};


// create class template with four policies and default values

template <typename PolicySetter1 = DefaultPolicyArgs,
          typename PolicySetter2 = DefaultPolicyArgs,
          typename PolicySetter3 = DefaultPolicyArgs,
          typename PolicySetter4 = DefaultPolicyArgs>
class BreadSlicer {
    typedef PolicySelector<PolicySetter1, PolicySetter2,
                           PolicySetter3, PolicySetter4>
            Policies;
    // use Policies::P1, Policies::P2, //... to refer to the various policies.
  public:
    void print () {
        Policies::P3::doPrint();
    }
    //...
};


// define a custom policy
class CustomPolicy {
  public:
    static void doPrint() {
        std::cout << "CustomPolicy::doPrint()\n";
    }
};

int main()
{
    BreadSlicer<> bc1;
    bc1.print();

    BreadSlicer<Policy3_is<CustomPolicy> > bc2;
    bc2.print();
}

空基类优化

定义
C++因为布局的需要,空类的大小一般不为0,通常为1,有的甚至为4。
C++规定,当空类作为基类时,只要不会与同一类型的对象或子对象分配到同一地址,就不需要为其分配任何空间,通常称为空类优化(EBCO)技术。

布局原则

实例分析1
class Empty {
    typedef int Int;  // typedef members don't make a class nonempty
};

class EmptyToo : public Empty {
};

class EmptyThree : public EmptyToo {
};

int main()
{
    std::cout << "sizeof(Empty):      " << sizeof(Empty)
              << '\n';
    std::cout << "sizeof(EmptyToo):   " << sizeof(EmptyToo)
              << '\n';
    std::cout << "sizeof(EmptyThree): " << sizeof(EmptyThree)
              << '\n';
}
在支持EBCO技术的编译器下,Empty、EmptyToo、EmptyThree的大小都为1。而在不支持EBCO技术的编译器下,Empty、EmptyToo、EmptyThree可能分别为1、2、3.
实例分析2
class Empty {
    typedef int Int;  // typedef members don't make a class nonempty
};

class EmptyToo : public Empty {
};

class NonEmpty : public Empty, public EmptyToo {
};

int main()
{
    std::cout << "sizeof(Empty):    " << sizeof(Empty) << '\n';
    std::cout << "sizeof(EmptyToo): " << sizeof(EmptyToo) << '\n';
    std::cout << "sizeof(NonEmpty): " << sizeof(NonEmpty) << '\n';
}
由于NonEmpty的基类EmptyToo和Empty不能分配到同一地址空间,否则EmptyToo的基类Empty和NonEmpty的基类Empty撞在同一地址空间,因此,NonEmpty的可能大小为2.

成员作基类

问题描述
在如下例子中:
template <typename T1, typename T2>
class MyClass
{
    T1 a;
    T2 b;
    ...
}
模板参数T1或T2之一或全部都有可能为空类,因此上面的类可能不能具有最优的布局,每个这样的实例都有可能浪费一个字的内存。
解决办法
借助EBCO的东风,采用继承的方式,示例如下:
template <typename Base, typename Member>
class BaseMemberPair : private Base {
  private:
    Member member;
  public:
    // constructor
    BaseMemberPair (Base const & b, Member const & m)
     : Base(b), member(m) {
    }

    // access base class data via first()
    Base const& first() const {
        return (Base const&)*this;
    }
    Base& first() {
        return (Base&)*this;
    }

    // access member data via second()
    Member const& second() const {
        return this->member;
    }
    Member& second() {
        return this->member;
    }
};

奇特的递归模板模式(CRTP)

定义和语法

派生类作为模板传给基类。
template <typename Derived>
class CuriousBase
{
    ...
}
class Curios: public CuriousBase<CuriousBase>
{
    ...
}

实例

1、记录类的实例化的个数
2、boost中的enable_shared_from_this类采用了此方法。

参数化虚拟性

定义和语法

定义
C++允许通过模板直接参数化3种实体:类型、常数和模板,同时,模板还能间接参数化其他特性,比如成员函数的虚拟性。
语法
class NotVirtual {
};

class Virtual {
  public:
    virtual void foo() {
    }
};

template <typename VBase>
class Base : private VBase {
  public:
    // the virtuality of foo() depends on its declaration
    // (if any) in the base class VBase
    // foo的虚拟性依赖于它在基类(如果存在基类的话)VBase的声明
    void foo() {
       std::cout << "Base::foo()" << '\n';
    }
};

template <typename V>
class Derived : public Base<V> {
  public:
    void foo() {
       std::cout << "Derived::foo()" << '\n';
    }
};

int main()S
{
    Base<NotVirtual>* p1 = new Derived<NotVirtual>;
    p1->foo();  // calls Base::foo()

    Base<Virtual>* p2 = new Derived<Virtual>;
    p2->foo();  // calls Derived::foo()
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值