这篇文章上次修改于 2320 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
2 C++及其标准库简介
C++标准化从1989年开始到1997年底完成。1998年9月公布。
template (模板)
模板是针对一个或多个尚未明确的型别编写的函数或类别。使用template时可以显式地(explicitly)或隐式地(implicitly)将型别作为参数进行传递。
template <class T>
inline const T& max(const T&a, const T&b)
{
//if a < b then use b else use a
return a < b ? b: a;
}
Nontype Template (非型别模板参数)
型别(type)可以作为template 的参数,非型别(nontype) 也可以作为template 的参数。
bitset<32> flags32;
bitset<50> flags50;
Default Template Parameters(缺省模板参数)
template <class T ,class containter = vector<T> >
class MyClass;
MyClass<int> x1;
MyClass<int, vector<int> >
关键字typename
template <class T>
class MyClass
{
typename T::SubType *ptr;
};
Member Template(成员模板)
class member function 可以是个template,但这样的member template既不能是virtual 也不能有缺省参数
class MyClass
{
template <class T>
void f(T);
};
Nested Template Classes
嵌套的(nested) classes 本身也可以是个template
template <class T>
class MyClass
{
template <class T2>
class NestedClass;
};
基本型别的显式初始化(Explicit Initialization)
如果采用不含参数的,明确的constructor(构造函数)调用语法,基本型会被初始化为零。
int i1;
int i2 = int();
下面这个函数可以保证x被初始化为0
template <class T>
void f()
{
T x = T();
};
异常处理(Exception Handing)
通过异常处理,c++标准库可以在不污染函数接口(亦即参数和返回值)的情况下处理异常。如果你遇到这样一个意外情况,可以通过抛出一个异常来停止一般的处理过程
class Error;
void f()
{
if(exception-condition)
{
throw Error();
}
}
语句throw开始了stack unwinding(堆栈辗转开解)过程。
命名空间(Namespaces)
Namespace将不同的标识符集合在一个具名作用域(named scope)内,如果你在namespace之内定义所有标识符号,则namespace本身名称就成了唯一可能与其他全局符号冲突的标识符号。
namespace josuttis
{
class File;
void myGlobalFunc();
}
josuttis::File obj;
使用using namespace josuttis;可以使namespace内的所有名字曝光。但是这样可能会出现命名冲突。
bool型别
为支持布尔值,c++增加了bool型别,bool可以增加程序的可读性,并允许你对布尔值实现重载操作。
false 0 , true 1;
关键字explicit
关键字explicit的作用,可以禁止"单参数构造函数(single argument constructor)"被用于自动类型转换。典型例子是群集类别(collection classed),你可以将初始长度作为参数传递给构造函数,利于可以声明一个构造函数,以stack的初始大小作为参数:
class Stack
{
explicit Stack(int size);
};
这里的explicit的应用非常重要,如果没有,这个构造函数有能力将一个int自动转型为stack,一旦出现,你可以给stack赋值一个整数而不引起任何问题。
Stack s;
s = 40;
自动类型转换会把40转换为有40个元素的stack并指派给s,如果我们将构造函数声明为explicit,上述赋值操作就会导致编译错误。
explicit同样可以阻绝"以赋值语法进行带有转型操作的初始化"
Stack s1(40);
Stack s2(40:
这是因为以下两组操作:
X x;
Y y(x); //explicit conversion
和
X x;
Y y = x; //implicit conversion
前者通过显式转换根据型别X产生了一个型别y的新对象,后者通过隐式转换,产生了一个型别Y的新对象。
新的型别转换操作符(Type Conversion Operators)
- static_cast 将一个值以符合逻辑的方式转型,这可以看作是“利用原值重建一个临时对象,并在设立初始值时使用类型转换”。唯一当上述的型别转换有所定义,这个转换才会成功。
float x;
cout << static_cast<int>(x);
f(static_cast<string>("hello"));
- dynamic_cast
将多态型别(polymorphic type)向下转型(downcast)为其实际静态型别(real static type).这是唯一在执行期进行检验的转型动作。
class Car;
class Cabriolet :public Car
{
...
};
class Limousine :public Car
{
..
};
void f(Car *p)
{
Cabriolet *p = dynamic_cast<Cabriolet*>(cp);
if(p == NULL) {
//..did not refer to an object of type Cabriolet
}
};
- const_cast
设定或去除型别的常数性(constness) 亦可以去除volatile修饰,除此之外不允许任何转换
- reinterpret_cast
此操作符的行为由编译器进行定义,可以重新解释bits意义,但也不一定如此,使用该转型动作统称会带来不可移植行。
常数静态成员(constant static members)的初始化
如今我们中午能够在class中对“整数型(integral)常数静态成员”直接赋予初值了。
const MyClass
{
static const int num =100;
int elems[num];
};
const int MyClass::num;
main()定义式
根据c++标准,只有两种main()是可移植的
int main()
{}
int main(int argc, char* argv[])
{}
Big-O表示法
常数 Q(1) 运行时间与元素个数无关
对数 O(log(n)) 运行时间随元素个数的增加呈对数增长
线性 O(n) 运行时间随元素个数的增加呈线性增长
n-log-n O(n*log(n)) 运行时间随元素个数的增加呈线性和对数的乘积增长
二次 O(n^2) 运行时间随元素个数的增加呈平方增长
没有评论