《C++标准程序库》第二章摘录与笔记
来源:互联网 发布:海康设备域名怎么设置 编辑:程序博客网 时间:2024/06/06 20:35
《C++标准程序库》第二章,摘录与笔记
2.2.1 模板
所谓“template”,是针对“一个或多个尚未明确的型别”所撰写的函数或类别。使用template时,可以显示或者隐式地将型别当做参数来传递。template并非一次编译便生出适合所有型别的代码,而是针对被使用的某个(或某组)型别进行编译。这导致一个重要的问题:实际处理template时,
面对函数模板,你必须先提供他的某个实作品,然后才能调用,如此方可通过编译。
————————————————————————————————————————————————————————————————————————
(摘录自《C++primer》16.3节模板编译模型)两种编译模型:两种模型中,构造程序的方式很大程度上是相同的:类模板定义和函数模板声明放在头文件中,而函数模板定义和类成员函数定义放在源文件中。
(与普通意义上的程序文件组织相同,但是不同的是:模板在进行实例化时需要编译器必须能够访问定义模板的源代码。所以当调用函数模板或类模板的成员函数的时候,
编译器需要函数的定义,需要那些通常放在源文件中的代码。)两种模型的不同在于,编译器怎样使用来自源文件的定义。
(1)包含编译模型。
编译器必须看到用到的所有模板的定义。一般而言,可以通过在声明函数模板或类模板的头文件中添加一条#include指示使定义可用,该#include引入了包含相关定义的源文件。
示例:
// header file test.h#ifndef TEST_H#define TEST_Htemplate <typename T> int func(const T&, const T&);// other declarations#include "test.cpp"// get the definitions for func etc.#endif // TEST_H// implementation file test.cpptemplate <typename T> int func(const T &v1, const T &v2){...... // define body}// other definitions
(2)分别编译模型。
编译器会为我们跟踪相关模板定义。我们必须让编译器知道要记住给定的模板定义,可以使用export关键字来做这件事(现有标准C++编译器的实现中大部分还未实现export用于分别编译模型)。export指明给定的定义可能会需要在其他文件中产生实例化。在一个程序中一个模板只能定义为一次。编译器在需要产生致谢实例化时及时出怎样定位模板定义。export不必再模板声明中出现。
————————————————————————————————————————————————————————————————————————
模板参数既可以有类型参数也可以有非类型参数,还可以提供默认参数。
标准C++还提供了typename关键字用于作为类型之前的标识符,指示之后的标识符为类型而不是非类型。如:
template <class T>class MyClass {typename T::SubType *ptr;...};这里ptr是一个类型的对象,而不是与之前标识符的乘积。此处任何用来取代T的类型,其内部必须提供一个内部类型SubType的定义。
如
class Q{typedef int SubType;// class SubType;// OK too....};C++的一般规则是,除了以typename修饰之外,template内部的任何标识符号都被视为一个值而非一个类型。
成员模板:
类成员函数可以是个模板,但这样的成员模板既不能是虚函数,也不能有缺省参数。如:
class MyClass{template <typename T>void func();...};这个特性通常为模板类中的成员提供自动类型转换。如:
template <typename T>class MyClass{private:T value;public:void assign(const MyClasls<T> &x){ // x must have same type as *thisvalue = x.value;}};即使两个类型可以自动转换,如果我们对assign使用不同的template类型,也会出错:
void func(){MyClass<double> d;MyClass<int> i;d.assign(d); // OKd.assign(i); // ERROR: i is MyClass<int> but MyClass<double> is required}使用成员模板设计类模板
template <typename T>class MyClass {private: T value;public:template <type X> // member template void assign(const MyClass<X> &x){ // allows different template typesvalue = x.getValue();}T getValue() const// {return value;}...};void func(){MyClass<double> d;MyClass<int> i;d.assign(d); // OKd.assign(i); // OK(int is assignable to double)}注意:在编译时,生成两个类型,d和i是两种不同的类型对象。而在类模板的定义中,成员模板assign参数x和*this类型不一定相同同,所以不能直接存取MyClass<>的private和protected成员,如在d.assign(i)编译时,(此时生成了一个新的类)assign参数的类型为MyClass<int>而*this的类型为MyClass<double>,这是两个不同的类,所以不能在一个类中直接使用另一个类的private和protected成员,可以使用共有成员函数进行处理,如上。
构造函数模板时成员模板的一种特殊形式。构造函数模板通常用于“在复制对象时实现隐式类型转换”。注意,构造函数模板并不遮蔽(hide)隐式拷贝构造函数(implicit copy constructor)。如果类型完全吻合,隐式拷贝构造函数就会被产生出来并被调用。如:
template <typename T>class MyClass{public:// copy sonstructor with implicit type conversion// -does not hide implicit copy constructortemplate <typename U>MyClass(const MyClass<U>& x);...};void func(){MyClass<double> xd;...MyClass<double> xd2(xd);// calls built-in copy constructorMyClass<int> xi(xd);// calls template constructor...}
2.2.2 基本类型的显示初始化
如果采用不含参数、明确的构造函数调用语法,基本类型会被初始化为0:int i1; // undefined value
int i2 = int(); // initialized with zero
这个特性可以确保我们在撰写模板代码时,任何类型都有一个确切的初值!如:
template <typename T>void f(){T x = T(); // x is initialized with zero...}
2.2.3 异常处理
通过异常处理,C++标准程序库可以在不“污染”函数接口(亦即参数和返回值)的情况下处理异常。可以运用所谓的异常规格来指明某个函数可能抛出哪些异常。如:
void f() throw(bad_alloc); // f()只可能抛出bad_alloc异常
如果声明一个空白异常规格,那就表明该函数不会抛出任何异常:
void f() throw(); // f()不抛出任何异常
2.2.6 关键字explicit
通过关键字explicit的作用,我们可以禁止“单参数构造函数”被用于自动类型转换。如:
class Stack{explict Stack(int size);// create stack with initial size...};Stack s;...s = 40; // Error,不会进行自动类型转换(int——>Stack)注意 explicit同样也能阻绝“以赋值语法进行带有转型操作的初始化”:
Stack s1(40); // OK
Stack s2 = 40; // Error,int 40无法转换为大小为40个元素的Stack。
原因:
X x;
Y y(x); // explicit conversion
和
X x;
Y y = x; // implicit conversion,会产生临时变量,效率也低
2.2.7 新的类型转换操作符
dynamic_cast类型转换操作符作用,将多态类型向下转型为其实际静态类型。(本来是子类类型,先经过向上转型后,现在向下转型则需要这个操作符)这是唯一在执行期进行检验的转型动作。你可以用它来检验某个多态对象的类型。(如果经过向下转换不是指向某个对象的静态类型,则返回NULL。若是向上转型时是引用则抛出异常)另外,C++提供的四个转型操作符只能接受一个参数,如果有多个参数,按逗号操作符对待,只是用最后一个参数。
2.2.8 常量静态成员
常量静态成员初始化,可以在类声明中直接对其进行初始化,这个常数便可以用于class之中,如:class MyClass{static const int num = 10;int elems[num];...};注意,你还必须为class之中声明的常量静态成员定义一个空间:
const int MyClass::num; // no initialization here
- 《C++标准程序库》第二章摘录与笔记
- 《C++标准程序库》第三章摘录与笔记
- 《C++标准程序库》第四章摘录与笔记
- 《C++标准程序库》第五章摘录与笔记
- 《C++标准程序库》第六章摘录与笔记
- 《C++标准程序库》学习笔记 -- 第二章
- 【C++标准程序库】第二章
- C++标准程序库 学习笔记 第二章 && 第三章
- 《C++标准程序库》第二章-C++及其标准程序库简介
- C标准程序库头文件
- C++标准程序库学习笔记
- 《STL标准程序库》笔记1
- 《STL标准程序库》笔记2
- 《STL标准程序库》笔记3
- 《STL标准程序库》笔记4
- 《STL标准程序库》笔记5
- C++标准程序库笔记---迭代器
- 阅读笔记《C++标准程序库》
- javascript 调试错误的方法
- mysql中索引的建立及利弊的分析
- Android OpenGL ES 开发教程(7):创建实例应用OpenGLDemos程序框架
- 读<企业应用架构模式>
- SoftReference
- 《C++标准程序库》第二章摘录与笔记
- C++中strcmp的头文件问题
- 浅看rabbitmq的mnesia部署
- 快速排序
- Android模拟器无法上网的原因
- oracle数据块详解
- 【大学生活】在软件学院的那些课
- ASP.NET MVC Controller与Areas下面的Controller同名的解决办法
- 百度文库中的plone教程