第七章 站在对象模型的尖端

第七章 站在对象模型的尖端

template的实例化行为

template<class Type>
class Point {
public:
    enum status { unallocated, normalized; }
    Point(Type x = 0.0, Type y = 0.0, TYpe z = 0.0);
    ~Point();
    void* operator() new (size_t);
    void operator() delete(void*, size_t);
private:
    static Point<Type> *freeList;
    static int chunksize;
    Type _x, _y, _z;
};

对于enum类型和static 成员,Point<float>Point<double> 会实例化两次,而且必须使用Point<flaot>::status 不能使用Point::statuc 来调用。

对于Point<float>* ptr = 0 编译器不需要实例化,因为其指向的对象是一个Point<float> 但其本身是一个指针,编译器没必要知道其内部的布局。但是对于Point<float> &ref = 0 编译器会通过如下方式将其实例化:

Point<float> tempory(float (0));
const Point<float> &ref = tempory;

模板类的成员函数只有在调用他的时候才会实例化,对于没有调用到的成员函数不会实例化。

template 的名称决议法

scope of the template definition 定义出template 的位置

scope of the template instantiation 实例化template 的位置

// scope of the template definition
extern double foo(double);
template <class type>
class ScopeRules {
public:
    void invariant() { _memeber = foo(_val); }
    type type_dependent() { return foo(_member); }
private:
    int _Val;
    type _member;
};

// scope of the template instantiation
extern int foo(int);
ScopeRules<int> src0;

src0.invariant() 调用的foodouble(foo) ,因为foo 的类型和实例化无关,对于scope来说只有double(foo) 这一种类型。

src0.type_depentent() 这里面foo 调用的是int foo(int) 函数的类型和实例化的类型有关,对于scope来说一共有double foo(double) int foo(int) 两种,这个时候因为_member 的类型为int 最终调用的是int foo(int) 类型。

但是如果src0unsigned int 或者 long 类型,会出现暧昧不清的情况。如果ScopeRules 按照 类类型进行实例化,如果没有定义向intdouble 的类型转换运算符,会报错。

保证安全的向下类型转换

dynamic_cast 可以在执行期决定其运行成本,如果向下类型转换是安全的回传回一个类型的指针,如果是不安全的回返回空指针。

class node {....};
class type : public node {....};
class fct : public type {...};
class gen : public type { ... };

typedef type *ptype;
typedef fct *pfct;
simplify_conv_op(ptype pt) {
    pfct pf = pfct(pt);	//这种类型转换是不安全的,
}

我们通过使用dynamic_cast来确保其类型的安全性。

simplify_conv_op(ptype pt) {
    if (pfct pf = dynamic_cast<pfct>(pt)) {
        // .....
    } else {// .....}
}

dynamic_cast如何确保其是安全的呢,以及为何dynamic_cast 相对于static_cast 的成本更高呢?

pfct 的一个类型描述器被编译器产生出来,由pt 指向的类对象描述其必须在执行期通过vptr获得。会发生如下的转换:

((type_info*)(pt->vptr[0]))->_type_descriptor

type_info类是C++定义的一个类型描述器类:

class type_info {
public:
    virtual ~type_info();
    bool operator==(const type_info& ) const;
    bool operator!=(const type_info& ) const;
    bool before(const type_info &) const;
    const char* name() const;
private:
    type_info(const type_info&);
    type_info& operator=(const type_info& );
}

虚函数表的第一个slot中包含type_info 的地址,两个类型描述器被交给runtime library 函数,比较之后告诉我们是否吻合。

dynamic_cast 也同样使用与引用,但是对于一个非类型安全的转换结果和指针不同。因为如果将一个引用设置为0,会产生一个临时性对象,临时性对象的初值被设置为0,引用被设置为临时性对象的别名。

dynamic_cast 作用于引用时会发生如下情况:

  • 如果引用真正参考到适当的派生类(包括下一层,下下一层等等),downcast 会被执行。
  • 如果引用不是一种真正的派生类,由于不能传回0,会抛出bad_cast 异常。
simplify_conv_op(const Type &rt) {
    try {
        fct &rf = dynamic_cast<fct&>(rt);
        ....
    } catch (bad_cast) {
        ...
    }
}

posted on 2022-12-20 22:59  翔鸽  阅读(17)  评论(0编辑  收藏  举报