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异 ...
随机推荐
- echo、print、print_r、var_dump
echo(): 可以一次输出多个值,多个值之间用逗号分隔.echo是语言结构(language construct),而并不是真正的函数,因此不能作为表达式的一部分使用. print(): 函数pri ...
- 快速认识LinkIt 7697开发板
LinkIt 7697是一款多功能且价格亲民的开发板,可用来连接网络或你的各项装置,同时提供Wi-Fi及蓝芽两种联机功能.此开发板采用MediaTek MT7697芯片,比起其他类似的Wi-Fi/蓝芽 ...
- 手动封装一个属于自己的AJAX类库
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 20155213 2016-2017-2 《Java程序设计》第二周学习总结
20155213 2016-2017-2 <Java程序设计>第二周学习总结 教材学习内容总结 关于Unicode和UTF 很抱歉,没能读完娄老师推荐的网址,关于Unicode和UTF的介 ...
- 20155307 2017-2018-2 《Java程序设计》第2周学习总结
20155307 2017-2018-2 <Java程序设计>第2周学习总结 教材学习内容总结 整数:short(2 byte).int(4 byte).long(8 byte) 字节(b ...
- tkinter菜单图标,工具栏
所用的图片: import tkinter as tk from tkinter import messagebox, filedialog, simpledialog, colorchooser f ...
- Azkaban系统的安装和分析。
Azkaban系统是一个数据处理的很好用的工具,可以用来运行hadoop任务,管理hdfs,可以进行schedule任务调度,总体来说功能还是很强大的. 研究了一下azkaban,做了以下总结性的东西 ...
- hive 空值、NULL判断
hive中空值判断基本分两种 (1)NULL 与 \N hive在底层数据中如何保存和标识NULL,是由 alter table name SET SERDEPROPERTIES('serializa ...
- .net core 部署 Docker 所遇到的几个问题
1.Connection reset by peer 造成这个问题的主要原因是在program.cs 文件中,未加入端口: public static IWebHostBuilder CreateWe ...
- XAF-如何修改内置的编辑器(Property Editor)
本示例演示在web/win中给 日期选择控制显示出一个时钟及修改时间的控件.效果如下: 如果你装了XAF在这个路径中已经有了这个示例: %PUBLIC%\Documents\DevExpress De ...