C++ Primer Plus学习:第十四章
第十四章 C++中的代码重用
包含对象成员的类
将类的对象作为新类的成员。称为has-a关系。使用公有继承的时候,类可以继承接口,可能还有实现(纯虚函数不提供实现,只提供接口)。使用包含时,可以获得实现,但是不能获得接口。
explicit关键字的用法:
防止单参数构造函数的隐式转换,例如定义了如下的构造函数:
Student::Student(const string &s, int n);
Student::Student(int n);
使用如下的定义:
Student st("Tom", 3);
st=5; //这样调用会调用Student::Student(int n)
//生成一个Student对象,将原来的对象覆盖
使用explicit关键字后,上面的调用会报错,使用方法如下:
explicit Student::Student(int n);
构造函数在构造继承对象之前,先构建继承对象与所有成员对象。
类构造函数中的成员初始化列表的初始化顺序按照类声明中变量定义的顺序,而不是初始化列表的顺序。
私有继承
私有继承是C++另一种实现has-a关系的途径。使用私有继承,基类的公共成员和保护成员都将成为派生类的私有成员。
对于继承类的构造函数,成员初始化列表中使用类名而不是成员名来标识构造函数,如:
Student::Student(const char * str, const double *pd, int n)
:std::string(str),valarray<double>(pd,n) { }
使用作用域解析符来调用基类的方法,如:
double Student::Average() const
{
if(valarray<double>::size()>0)
return valarray<double>::sum()/valarray<double>::size();
else
return 0;
}
访问基类对象的方法:使用强制类型转换
const string &Student::Name() const
{
return (const string &) *this;
}
访问基类的友元函数:
os<<(const string &)stu<<std::endl;
多重继承
class SingingWaiter: public Waiter, public Singer {…};
如果不指定继承方式为public,默认为private。
如果多重继承的类含有一个共同基类,则会产生问题。即加入Waiter和Singer均继承自Worker类,则SingingWaiter将会产生两个Worker的副本,在使用多态性时将会产生二义性问题。可以使用强制类型转换解决一部分问题,如:
SingingWaiter ed;
Worker * pw1=(Waiter *)&ed;
Worker * pw2=(Singer *)&ed;
我们可以使用虚基类技术解决这个问题
虚基类
虚基类使得从多个类(基类相同)派生出来的对象只继承一个基类对象。在类声明中使用关键字virtual 即可。
如:
class Singer: virtual public Worker{};
class Waiter: public virtual Worker{};
定义SingingWaiter如下:
class SingingWaiter: public Singer, public Waiter {…};
SingingWaiter对象中只含有Worker对象的一个副本。
C++在基类是虚的时候,禁止信息通过中间类自动传递给基类。即不能通过调用Waiter构造函数来调用Worker类的构造函数构造Worker,故SingingWaiter类的构造函数如下:
SingingWaiter(const Worker & wk, int p=0, int v=Singer::other)
:Worker(wk), Waiter(wk,p), Singer(wk,v) {}
通过直接调用Worker类的构造函数来构造Worker对象。
若想调用基类中相同的函数,使用作用域解析符
void SingingWaiter::Show()
{
Singer::Show();
}
类模板
C++的类模板为生成通用的类声明提供了一种更好的办法,模板提供参数化类型,即能够将类型名作为参数传递给接收方来建立类或者函数。
C++提供了很多模板类,如valarray,vector,array和STL(标准模板库)。
由于模板不是函数,他们不能单独编译,所以模板必须与特定的模板实例化请求一起使用。为此,最简单的方法就是将所有模板信息放在一个头文件中,并在要使用这些模板的文件中包含该头文件。
定义模板类
表 0-1 模板类stacktp.h
//stacktp.h – a stack template #ifndef STACKTP_H_ #define STACKTP_H_ template <class Type> class Stack { private: enum{MAX=10}; // Type items[MAX]; int top; //栈顶索引 public: Stack(); bool isempty(); bool push(const Type & item); //压栈 bool pop(Type & item); //出栈 }
template<class Type> Stack<Type>::Stack() { top=0; }
template<class Type> bool Stack<Type>::isempty() { return top==0; }
template<class Type> bool Stack<Type>::isfull() { return top==MAX; }
template<class Type> bool Stack<Type>::push(const Type & item) { if(top<MAX) { items[top++]=item; return true; } else return false; }
template<class Type> bool Stack<Type>::pop(const Type & item) { if(top>0) { item=items[--top]; return true; } else return false; } #endif |
非类型参数
template<class T, int n>
int n指定特殊的类型而不是用作泛型名称为非类型或表达式参数。
表达式参数有一些限制,可以为整型、枚举、引用或者指针。double m不合法,但是double * pm和double& rm合法。模板代码不能修改表达式的值,也不能使用使用参数的地址。实例化模板时,用作表达式参数的值必须是常量表达式。
模板的具体化
隐式实例化:
stacktp<int> stp; //声明一个类并实例化一个对象
或者
stacktp<int> *pst;//仅声明一个指针
pst=new stacktp<int>; //创建一个对象
显式实例化
template class stacktp<int>;
显式具体化
template <> class Classname<specialized-type-name> {…};
如:template <> class stacktp<const char *>{};//重定义stacktp
部分具体化:
//通用模板
template <class T1, class T2> class Pair{…};
template <class T1> class Pair<T1,int> {…};
template<> class Pair<int, int> {…};
编译器将根据具体化程度最高的模板
Pair<double,double> p1;//通用模板
Pair<double,int> p2;//Pair<T1,int>模板
Pair<int,int> p3;//Pair<int,int>模板
template<class T> class Feeb{…};
template<class T*> class Feeb{…};
Feeb<char> fb1;//调用第一个
Feeb<char *> fb2;//调用第二个
成员模板
模板可以作为结构、类或者模板类的成员
表 0-2 tempmemb.h
//tempmemb.h – template as member of template class #include<iostream.h> using std::cout; using std::endl; template <typename T> class beta { private: template <typename V> class hold { private: V val; public: hold(V v=0):val(v){} void show() const {cout<<val<<endl;} V Value() const {return val;} }; hold<T> q; hold<int> n; public: beta(T t,int i):q(t),n(i){} template<typename U> //函数模板 U blab(U u,T t){return (n.Value()+q.Value)*u/t;} void show() const{q.show();n.show();} } ; |
将模板用作参数
template <template <typename T> class Thing>
class Crab
Thing必须是一个模板类
Crab<Stack>
模板类和友元
模板类的非模板友元函数
template<class T>
class HasFriend
{
friend void report(HasFriend<T> &);
};
模板类的约束模板友元函数
模板类的约束模板友元函数
先声明模板函数
template <typename T> void counts();
声明模板类
template <typename TT>
class HasFriendT
{
friend void counts<TT>();
friend void report<>(HasFriend<TT> &);
};
模板类的非约束模板友元函数
template <typename T>
class ManyFriend
{
template <typename C, typename D> friend void show2(C &,D &);
};
C++ Primer Plus学习:第十四章的更多相关文章
- C++ Primer Plus学习:第四章
C++入门第四章:复合类型 1 数组 数组(array)是一种数据格式,能够存储多个同类型的值. 使用数组前,首先要声明.声明包括三个方面: 存储每个元素中值的类型 数组名 数组中的元素个数 声明的通 ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十四章:曲面细分阶段
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十四章:曲面细分阶段 代码工程地址: https://github. ...
- 《Linux命令行与shell脚本编程大全》 第十四章 学习笔记
第十四章:呈现数据 理解输入与输出 标准文件描述符 文件描述符 缩写 描述 0 STDIN 标准输入 1 STDOUT 标准输出 2 STDERR 标准错误 1.STDIN 代表标准输入.对于终端界面 ...
- 【C++】《C++ Primer 》第十四章
第十四章 重载运算与类型转换 一.基本概念 重载运算符是具有特殊名字的函数:由关键字operator和其后要定义的运算符号共同组成.也包含返回类型.参数列表以及函数体. 当一个重载的运算符是成员函数时 ...
- 第十四章——循环神经网络(Recurrent Neural Networks)(第二部分)
本章共两部分,这是第二部分: 第十四章--循环神经网络(Recurrent Neural Networks)(第一部分) 第十四章--循环神经网络(Recurrent Neural Networks) ...
- “全栈2019”Java多线程第三十四章:超时自动唤醒被等待的线程
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第二十四章:等待唤醒机制详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第十四章:线程与堆栈详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java异常第十四章:将异常输出到文本文件中
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
随机推荐
- php设置文件类型content-type
在PHP中可以通过header函数来发送头信息,还可以设置文件的content-type,下面整理了一些常见文件类型对于的content-type值. //date 2015-06-22//定义编码h ...
- angular中的$cookies和$cookieStore设置过期时间
angular1.4及以上版本才支持$cookies. 项目引入的是1.4.2版本,操作cookies原先一直用的是$cookieStore,用的飞起啊. $cookieStore.remove(&q ...
- NIH周三讲座视频爬虫
最近网是越来越差了,在线播放基本是没戏了,所以就动了爬虫下载的念头. NIH把视频片段存放,一般都是8秒一段,大概看下视频长度估算一下片段个数就差不多了. 新建一个NIH的文件夹,然后把爬虫下来的.t ...
- SSM-CRUD入门项目——删除
删除 分析 可以进行单个删除,直接点击每条记录后的删除按钮 批量删除,通过勾选checkbox框进行选择删除 单个删除: 通过发送DELETE请求的URL:/emp/{id} 这次我们先从contro ...
- 20155234 《Java程序设计》实验四 (Android程序设计)实验报告
实验内容 基于Android Studio开发简单的Android应用并部署测试; 了解Android.组件.布局管理器的使用: 掌握Android中事件处理机制. 实验步骤 (一)Android S ...
- mycp 补交作业
老师好:我昨天做完时已经是11点多了,错过了提交时间,希望用此篇博客弥补一下我的过失. import java.io.; import java.lang.; import java.util.Sca ...
- 20145226夏艺华 《Java程序设计》实验报告五
实验五 Java网络编程及安全 实验内容 运行下载的TCP代码,结对进行 利用加解密代码包,编译运行代码,结对进行 集成代码,加密后通过TCP发送 结对伙伴:20145203 马超 实验步骤 (一)中 ...
- python 多线程笔记(4)-- 车站售票模拟
import threading import time import random class Worker(threading.Thread): '''售票员''' def __init__(se ...
- day1 创建X00001文件1K
要求:创建文件名为:X000001-X999999,大小为1K 的文件 版本1) import os #1.输入要创建的文件数量 nums = int(input("nums:") ...
- 【MySQL数据库权限】RDS for MySQL创建高权限账号
原文转自:https://help.aliyun.com/document_detail/26130.html?spm=5176.2020520104.201.1.580be8abjlGorJ 为满足 ...