当前位置:天才代写 > tutorial > C语言/C++ 教程 > 《深度摸索C++工具模子》念书条记(7)

《深度摸索C++工具模子》念书条记(7)

2017-11-05 08:00 星期日 所属: C语言/C++ 教程 浏览:320

副标题#e#

***Template的“具现”行为***

template class中的任何member都只能通过template class的某个实体来存取或操纵。

Point<float>::Status s;  // ok
Point::Status s;  // error

假如我们界说一个指针,指向特定的实体,像这样:

Point<float> *ptr = 0;

由于这是一个指向class object的指针,自己并不是一个class object,编译器不需要知道与该class有关的任何members数据。所以将“Point的一个float实体”具现也就没有须要。

假如不是一个pointer而是reference ,假设:

Point<float> &ref = 0;

这个界说的真正语领悟被扩 展为:

// 内部扩展
Point<float> temp(float(0));
Point<float> &ref = temp;

以上转化是因为reference并不是无物(no object)的代名词,0被视作整数,必需被转换为范例Point<float>的一个工具。

然而, member functions只有在member functions被利用的时候,C++ Standard才要求它们被“具现 ”出来。这个法则的由来主要有两个原因:

(1)空间和效率的思量。对付未利用的函数进 行“具现”将会耗费大量的时间和空间;

(2)尚未实现的成果。并不是一个 template具现出来的所有范例必然可以或许完整支持一组member functions,因而只需具现真正需要的 member functions.

举个例子:

Point<float> *p = new Point<float>;

只有(a)Point template的float实例、(b)new 运算符、(c) default constructor需要被“具现”。

***Template的错误陈诉***

所有与类 型相关的检讨,假如涉及到template参数,都必需延迟到真正的具现操纵产生。

对付下面的 template声明:

template <class T>
class Mumble
{
public:
Mumble(T t = 1024) : _t(t)
{
if(tt != t)
throw ex ex;
}
private:
T tt;
}

个中像“T t = 1024”、“tt != t”这样的潜在错误在template声明时并不会陈诉,而会在每个具现操纵产生时被查抄出来并记录 之,其功效将因差异的实际范例而差异。

Mumble<int> mi;  // 上述两个潜在错 误都不存在
Mumble<int*> pmi;  // 由于不能将一个非零的整数常量指定给一个指针,故 “T t = 1024”错误


#p#副标题#e#

***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() { _member = foo(_val); }
type type_dependent() { return foo(_member); }
// ...
private:
int _val;
type _member;
};

// scope of the template instantiation
extern int foo(int);

ScopeRules<int> sr0;

在“scope of the template definition”中,只有一个foo()函数声明位于scope之内;然而在“scope of the template instantiation”中,两个foo()函数声明都位于scope之内。对付以下函数操纵:

// scope of the template instantiation
sr0.invariant();

那么 ,在invariant()中挪用的毕竟是哪一个foo()函数实体呢?

Template之中,对付一个 nonmember name的决策功效是按照这个name的利用是否与“用以具现出该template的参数范例 ”有关而抉择的,假如其利用互不相关,那么就以“scope of the template definition”来抉择name,不然就以“scope of the template instantiation”来决 定name.

// 因为_val的范例是int,而函数的决策只和函数原型有关,与函数返回值无关
// 被用来具现这个template的真正范例对付_val的范例没有影响
_member = foo (_val);

故此处的挪用操纵由“scope of the template definition”来决策 。

若是如下的函数挪用:

sr0.type_dependent();

由于_member的范例与 template参数有关,故此处由“scope of the template instantiation”来决策。

***Member Function的具现行为***

以手动方法在个此外object module中完成预先具现 操纵,是独一有效率的步伐。

***执行期范例识别***

dynamic_cast运算符可以在执行期 抉择真正的范例。假如downcast是安详的(也就是说,一个base type pointer指向一个derived class object),这个运算符会传回被适当转型过的指针;假如downcast不是安详的,这个运算符会传回 0.

#p#分页标题#e#

typedef type *ptype;
typedef fct *pfct;

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

什么是dynamic_cast的真正本钱?pfct的一个范例描写器会被编 译器发生出来,由pt指向之class object范例描写器必需在执行期通过vptr取得。下面是大概的转换:

// 取得pt的范例描写器
((type_info*)(pt->vptr[0]))- >_type_description;

个中,type_info是C++ Standard所界说的范例描写器的class 名称,该class中安排着待索求的范例信息。virtual table的第一个slot内含type_info object的地点 ,此type_info object与pt所指之class type有关。

dynamic_cast运算符也合用于reference身 上,然而对付一个non-type-safe-cast,其功效不会与施行于指针的环境一样。一个reference不行以像 指针那样“把本身设为0便代表了no object”;若将一个reference设为0,会引起一个姑且 性工具(拥有被参考到的范例)被发生出来,该姑且工具的初值为0,这个reference然后被设定为该临 时变量的一个体名。

因而,假如reference并不真正是某一种derived class,那么可通过丢出一 个bad_cast exception举办处理惩罚:

simplify_conv_op(const type &rt)
{
try {
fct &rf = dynamic_cast<fct&>(rt);
}
catch(bad cast) {
// ...
}
}

虽然,你也可以利用typeid运算符来到达同样的目标:

simplify_conv_op(const type &rt)
{
if(typeid(rt) == typeid (fct))
{
fct &rf = dynamic_cast<fct&>(rt);
}
else { ... }
}

 

    关键字:

天才代写-代写联系方式