C++基础(9)

C++基础(9)

valarray类
valarray类是由头文件valarray支持的。顾名思义,这个类由于处理数值(或是具有类似特性的类),它支持诸如将数组所有元素的至值相加以及在数组中找出最大和最小的值等操作。valarray被定义为一个模板类,以便能够处理不同的数据类型。使用valarray类来声明一个对象时,需要在标识符valarray后面加上一对尖括号,并在其中包含所需的数据类型:

valarray<int> q_values;
valarray<double> weights;

类方法:

  • operator :让您能够访问各个元素。
  • size():返回包含的元素数。
  • sum():返回所有元素的总和。
  • max():返回最大的元素。
  • min():返回最小的元素。

私有继承
C++还有另一种实现has-a关系的途径——私有继承。使用私有继承,基类的公有成员和保护成员都将成为派生类的私有成员。这意味着基类方法将不会成为派生类对象公有接口的一部分,但可以在派生类的成员函数中使用它们。

多重继承
MI描述的是有多个直接基类的类。与单继承一样,公有MI表示的也是is-a关系。例如,可以从Waiter类和Singer类派生出SingingWaiter类:

class SingingWaiter : public Waiter, public Singer {...};

类模板
C++的类模板为生成通用的类声明提供了一种更好的方法(C++最初不支持模板,但模板被引人后,就一直在演化,因此有的编译器可能不支持这里介绍的所有特性)。模板提供参数化( parameterized )类型,即能够将类型名作为参数传递给接收方来建立类或函数。例如,将类型名int传递给Queue模板,可以让编译器构造一个对int进行排队的Queue类。

友元类
将类作为友元的情况下,友元类的所有方法都可以访问原始类的私有成员和保护成员。另外,也可以做更严格的限制,只将特定的成员函数指定为另一个类的友元。哪些函数、成员函数或类为友元是由类定义的,而不能从外部强加友情。因此,尽管友元被授予从外部访问类的私有部分的权限,但它们并不与面向对象的编程思想相悖;相反,它们提高了公有接口的灵活性。

嵌套类
在C++中,可以将类声明放在另一个类中。在另一个类中声明的类被称为嵌套类(nested class),它通过提供新的类型类作用域来避免名称混乱。包含类的成员函数可以创建和使用被嵌套类的对象;而仅当声明位于公有部分,才能在包含类的外面使用嵌套类,而且必须使用作用域解析运算符(然而,旧版本的C++不允许嵌套类或无法完全实现这种概念)。

异常
对异常的处理有3个组成部分:

  • 引发异常
  • 使用处理程序捕获异常
  • 使用try块

String类
string类是由头文件string支持的(注意,头文件string.h和cstring支持对C-风格字符串进行操纵的C库字符串函数,但不支持string类)。要使用类,关键在于知道它的公有接口,而string类包含大量的方法,其中包括了若干构造函数,用于将字符串赋给变量、合并字符串、比较字符串和访问各个元素的重载运算符以及用于在字符串中查找字符和子字符串的工具等。简而言之,string 类包含的内容很多。

标准模板库
STL提供了一组表示容器、迭代器、函数对象和算法的模板。容器是一个与数组类似的单元,可以存储若干个值。STL容器是同质的,即存储的值的类型相同;算法是完成特定任务(如对数组进行排序或在链表中查找特定值)的处方;迭代器能够用来遍历容器的对象,与能够遍历数组的指针类似,是广义指针;函数对象是类似于函数的对象,可以是类对象或函数指针( 包括函数名,因为函数名被用作指针)。STL使得能够构造各种容器(包括数组、队列和链表)和执行各种操作(包括搜索、排序和随机排列)。

泛型编程
泛型编程旨在编写独立于数据类型的代码。在C++中,完成通用程序的工具是模板。当然,模板使得能够按泛型定义函数或类,而STL通过通用算法更进了一步。模板让这一切成为可能, 但必须对元素进行仔细地设计。

总结

C++提供了几种重用代码的手段。公有继承能够建立is-a关系,这样派生类可以重用基类的代码。私有继承和保护继承也使得能够重用基类的代码,但建立的是has-a 关系。使用私有继承时,基类的公有成员和保护成员将成为派生类的私有成员;使用保护继承时,基类的公有成员和保护成员将成为派生类的保护成员。无论使用哪种继承,基类的公有接口都将成为派生类的内部接口。这有时候被称为继承实现,但并不继承接口,因为派生类对象不能显式地使用基类的接口。因此,不能将派生对象看作是一种基类对象。由于这个原因,在不进行显式类型转换的情况下,基类指针或引用将不能指向派生类对象。
还可以通过开发包含对象成员的类来重用类代码。这种方法被称为包含、层次化或组合,它建立的也是has-a关系。与私有继承和保护继承相比,包含更容易实现和使用,所以通常优先采用这种方式。然而,私有继承和保护继承比包含有一些不同的功能。例如,继承允许派生类访问基类的保护成员;还允许派生类重新定义从基类那里继承的虚函数。因为包含不是继承,所以通过包含来重用类代码时,不能使用这些功能。另一方面,如果需要使用某个类的几个对象,则用包含更适合。例如,State 类可以包含一组County对象。
多重继承(MI)使得能够在类设计中重用多个类的代码。私有MI或保护MI建立has-a关系,而公有MI建立is-a关系。MI会带来一些问题,即多次定义同一个名称,继承多个基类对象。可以使用类限定符来解决名称二义性的问题,使用虚基类来避免继承多个基类对象的问题。但使用虚基类后,就需要为编写构造函数初始化列表以及解决二义性问题引人新的规则。
类模板使得能够创建通用的类设计,其中类型(通常是成员类型)由类型参数表示。典型的模板如下:

template <class T>
class Ic
{
	T v;
	...
public:
	Ic(const T & val):v(val) {}
...
};

其中,T是类型参数,用作以后将指定的实际类型的占位符(这个参数可以是任意有效的C++名称,但通常使用T和Type)。在这种环境下,也可以使用typename代替class:

template <typename T> // same as template <class T>
class Rev {...};

类定义(实例化)在声明类对象并指定特定类型时生成。例如,下面的声明导致编译器生成类声明,用声明中的实际类型short 替换模板中的所有类型参数T:

class Ic<short> sic; // implicit instantiation

这里,类名为Ic,而不是Ic。Ic称为模板具体化。具体地说,这是一个隐式实例化。使用关键字template声明类的特定具体化时,将发生显式实例化:

template class IC<int>; // explicit instantiation

在这种情况下,编译器将使用通用模板生成一个int具体化——lc, 虽然尚未请求这个类的对象。
可以提供显式具体化——覆盖模板定义的具体类声明。方法是以template<>打头,然后是模板类名称,再加上尖括号(其中包含要具体化的类型)。例如,为字符指针提供专用Ic类的代码如下:

template <> class Ic<char *>.
{
	char * str;
	...
public:
	Ic(const char * s) : str(s) {}
}

这样,下面这样的声明将为chic使用专用定义,而不是通用模板:

class Ic<char *> chic;

类模板可以指定多个泛型,也可以有非类型参数:

template <class T, class TT, int n>

class Pals {... };

下面的声明将生成一个隐式实例化,用double代替T,用string代替TT,用6代替n:

Pals<double, string, 6> mix;

类模板还可以包含本身就是模板的参数:

template < template <typename T> class CL, typename U, int z>

class Trophy {...};

其中z是一个int值, U为类型名,CL为一个使用tmplate-ypename, T>声明的类模板。

类模板可以被部分具体化:

template <class T> Pals<T, T, 10> {...};

template <class T, class TT> Pals<T, TT,100> {...};

template <class T, int n> Pals <T,T*, n> {...};

第一个声明为两个类型相同,且n的值为10的情况创建了一个具体化。同样,第二个声明为n等于100的情况创建了一个具体化; 第三个声明为第二个类型是指向第一个类型的指针的情况创建了一个具体化。模板类可用作其他类、结构和模板的成员。

所有这些机制的目的都是为了让程序员能够重用经过测试的代码,而不用手工复制它们。这样可以简化编程工作,提供程序的可靠性。

友元使得能够为类开发更灵活的接口。类可以将其他函数、其他类和其他类的成员函数作为友元。在某些情况下,可能需要使用前向声明,需要特别注意类和方法声明的顺序,以正确地组合友元。

嵌套类是在其他类中声明的类,它有助于设计这样的助手类,即实现其他类,但不必是公有接口的组成部分。

C++异常机制为处理拙劣的编程事件,如不适当的值、I/O失败等,提供了一种灵活的方式。引发异常将终止当前执行的函数,将控制权传给匹配的catch块。catch块紧跟在try块的后面,为捕获异常,直接或间接导致异常的函数调用必须位于try块中。这样程序将执行catch 块中的代码。这些代码试图解决问题或终止程序。类可以包含嵌套的异常类,嵌套异常类在相应的问题被发现时将被引发。函数可以包含异常规范,指出在该函数中可能引发的异常;但C++11摒弃了这项功能。未被捕获的异常(没有匹配的catch块的异常)在默认情况下将终止程序,意外异常(不与任何异常规范匹配的异常)也是如此。RTTI (运行阶段类型信息)特性让程序能够检测对象的类型。dynamic cast 运算符用于将派生类指针转换为基类指针,其主要用途是确保可以安全地调用虚函数。Typeid运算符返回一个type_info 对象。可以对两个typeid的返回值进行比较,以确定对象是否为特定的类型,而返回的type_info 对象可用于获得关于对象的信息。

与通用转换机制相比,dynamic_cast、 static_cast 、const_cast和reinterpret_cast 提供了更安全、更明确的类型转换。
C++提供了一组功能强大的库,这些库提供了很多常见编程问题的解决方案以及简化其他问题的工具。string类为将字符串作为对象来处理提供了一种方便的方法。string 类提供了自动内存管理功能以及众多处理字符串的方法和函数。例如,这些方法和函数让您能够合并字符串、将一个字符串插人到另一个字符串中、反转字符串、在字符串中搜索字符或子字符串以及执行输人和输出操作。

诸如auto_ptr以及C++11新增的shared_ptr和unique_ptr等智能指针模板使得管理由new分配的内存更容易。如果使用这些智能指针(而不是常规指针)来保存new返回的地址,则不必在以后使用删除运算符。智能指针对象过期时,其析构函数将自动调用delete运算符。

STL是一个容器类模板、迭代器类模板、函数对象模板和算法函数模板的集合,它们的设计是致的,都是基于泛型编程原则的。算法通过使用模板,从而独立于所存储的对象的类型;通过使用迭代器接口,从而独立于容器的类型。迭代器是广义指针。

STL使用术语“概念”来描述一组要求。 例如,正向迭代器的概念包含这样的要求,即正向迭代器能够被解除引用,以便读写,同时能够被递增。概念真正的实现方式被称为概念的“模型”。例如,正向迭代器概念可以是常规指针或导航链表的对象。基于其他概念的概念叫作“改进”。例如,双向迭代器是正向迭代器概念的改进。

诸如vector和set等容器类是容器概念( 如容器、序列和关联容器)的模型。STL 定义了多种容器类模板: vector、deque、 list、 set、mutiset、 map、 multimap和bitset;还定义了适配器类模板queue、priority_queue和stack;这些类让底层容器类能够提供适配器类模板名称所建议的特性接口。因此,stack 虽然在默认情况下是基于vector的,但仍只允许在栈顶进行插入和删除。C++11 新增了forward_list、unordered_set、unordered_multiset、unordered_map和unordered_multimap。

有些算法被表示为容器类方法,但大量算法都被表示为通用的、非成员函数,这是通过将迭代器作为容器和算法之间的接口得以实现的。这种方法的一个优点是:只需一个诸如for_each()或copy()这样的函数,而不必为每种容器提供一个版本; 另一一个优点是: STL 算法可用于非STL容器,如常规数组、string 对象、array对象以及您设计的秉承STL迭代器和容器规则的任何类。

容器和算法都是由其提供或需要的迭代器类型表征的。应当检查容器是否具备支持算法要求的迭代器概念。例如,for_each()算法使用一个输入迭代器,所有的STL容器类类型都满足其最低要求;而sort()则要求随机访问迭代器,并非所有的容器类都支持这种迭代器。如果容器类不能满足特定算法的要求,则可能提供一个专用的方法。例如,list 类包含一个基于双向迭代器的sort()方法,因此它可以使用该方法,而不是通用函数。

STL还提供了函数对象(函数符),函数对象是重载了()运算符(即定义了operator()()方法)的类。可以使用函数表示法来调用这种类的对象,同时可以携带额外的信息。自适应函数符有typedef语句,这种语句标识了函数符的参数类型和返回类型,这些信息可供其他组件(如函数适配器)使用。

通过表示常用的容器类型,并提供各种使用高效算法实现的常用操作(全部是通用的方式实现的),STL提供了一个非常好的可重用代码源。可以直接使用STL工具来解决编程问题,也可以把它们作为基本部件,来构建所需的解决方案。

模板类complex和valarray支持复数和数组的数值运算。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Capsule。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值