第14章 C++中的代码重用
2020-02-24 10:31:14 8 举报
AI智能生成
C++ Plus 笔记
作者其他创作
大纲/内容
其他
初始化列表的初始化顺序
一般次序
调用基类构造函数,调用顺序按照他们被继承时声明的顺序(右到左)
对派生类新增的成员对象初始化,调用顺序按照他们在类中声明的顺序
执行派生类的构造函数体的顺序
例子
代码
<div>#include<iostream></div><div>using namespace std;</div><div>class Base1{</div><div>public:</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Base1(int i){cout<<"constructing Base1 "<<i<<endl;}</div><div>};</div><div><br></div><div>class Base2{</div><div>public:</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Base2(int j){cout<<"constructing Base2 "<<j<<endl;}</div><div>};</div><div><br></div><div>class Base3{</div><div>public:</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Base3(){cout<<"constructing Base3* "<<endl;}</div><div>};</div><div><br></div><div>class Derived:public Base2,public Base1,public Base3{</div><div>public:</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Derived(int a,int b,int c,int d):Base1(a),member2(d),member1(c),Base2(b)</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>{}</div><div>private:</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Base1 member1;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Base2 member2;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Base3 member3;</div><div>};</div><div><br></div><div>int main()</div><div>{</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Derived obj(1,2,3,4);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>return 0;</div><div>}<br></div>
结果
<div>constructing Base2 2</div><div>constructing Base1 1</div><div>constructing Base3*</div><div>constructing Base1 3</div><div>constructing Base2 4</div><div>constructing Base3*<br><br></div>
说明
与初始化顺序没有关系
指向指针的引用
http://blog.csdn.net/acs713/article/details/12508049
(1)指向指针的引用,不仅改变了指针所指的对象,也改变了指针本身。
(2)指向指针的引用,可以实现对传递给形参的实参数值的交换。即指向指针的引用可以修改指针的值,在参数传递时是传址。
包含对象成员的类
valarray类的简介
简介
是一个模板类
头文件
#include<valarray>
声明
1
valarray<double> q_values;<br>valarray<int> weights; // 长度为0的 int 数组
2
valarray<int> v2(8); // 长度为8的 int 数组
3
valarray<int> v3( 10 , 8 ) // an array of 8 int elements , each set to 10
4
double gap[5] = { 3.1, 3.5 , 3.8 , 2.9 , 3.3 }<br>valarray<int> <b>v4( gpa, 4 )</b>; // an array of 4 elements ,initialzed to the first 4 elements of gpa;
C++11
valarray<int> v5 ={ 20, 32, 17, 9}; //可以使用初始化标
常用方法<br>v. xx()
operator[]()
能访问各个元素
size()
返回包含的元素数
sum()
返回所用元素的总和
max()
返回最大的元素
子主题
返回最小的元素
student 类设计
student 与 <br>string,valarray关系
不是is-a,是has-a关系
is-a 关系——继承,获得继承接口和实现
has-a 关系——组合(包含),获得实现,不能获得接口
类设计
class student<br>{<br>private:<br> string name;<br> valarray<double> score;<br> ....<br>}
name 、score都是分别是类string,valarray的对象
结果
能使用 string 和 valarray<double> 类的公有接口来访问和修改 name和scores对象
Student类没有继承string 和 valarray<double> 的公有接口
如果类的接口部分对新类有意义,可以..
例如:希望使用string接口中的operator<( ) 方法将Student对象按姓名进行排序,<br>为此可定义 Student::operator<( ) 成员函数,在内部使用函数string::operator<( )
student示例
总代码
类声明
// studentc.h -- defining a Student class using containment<br>#ifndef STUDENTC_H_<br>#define STUDENTC_H_<br><br>#include <iostream><br>#include <string> <br>#include <valarray><br>class Student<br>{ <br>private:<br> typedef std::valarray<double> ArrayDb;<br> std::string name; // contained object<br> ArrayDb scores; // contained object<br> // private method for scores output<br> std::ostream & arr_out(std::ostream & os) const;<br>public:<br> Student() : name("Null Student"), scores() {}<br> explicit Student(const std::string & s)<br> : name(s), scores() {}<br> explicit Student(int n) : name("Nully"), scores(n) {}<br> Student(const std::string & s, int n)<br> : name(s), scores(n) {}<br> Student(const std::string & s, const ArrayDb & a)<br> : name(s), scores(a) {}<br> Student(const char * str, const double * pd, int n)<br> : name(str), scores(pd, n) {}<br><br> ~Student() {}<br> double Average() const;<br> const std::string & Name() const;<br> double & operator[](int i);<br> double operator[](int i) const;<br><br> // friends<br> // input<br> friend std::istream & operator>>(std::istream & is,<br> Student & stu); // 1 word<br> friend std::istream & getline(std::istream & is,<br> Student & stu); // 1 line<br> <br> // output<br> friend std::ostream & operator<<(std::ostream & os,<br> const Student & stu);<br>};
类定义
//public methods<br>double Student::Average() const<br>{<br> if (scores.size() > 0)<br> return scores.sum()/scores.size(); <br> else<br> return 0;<br>}<br><br>const string & Student::Name() const<br>{<br> return name;<br>}<br><br>double & Student::operator[](int i)<br>{<br> return scores[i]; // use valarray<double>::operator[]()<br>}<br><br>double Student::operator[](int i) const<br>{<br> return scores[i];<br>}<br><br>// private method<br>ostream & Student::arr_out(ostream & os) const<br>{<br> int i;<br> int lim = scores.size();<br> if (lim > 0)<br> {<br> for (i = 0; i < lim; i++)<br> {<br> os << scores[i] << " ";<br> if (i % 5 == 4)<br> os << endl;<br> }<br> if (i % 5 != 0)<br> os << endl;<br> }<br> else<br> os << " empty array ";<br> return os; <br>}<br><br>// friends<br><br>// use string version of operator>>()<br>istream & operator>>(istream & is, Student & stu)<br>{<br> is >> stu.name;<br> return is; <br>}<br><br>// use string friend getline(ostream &, const string &)<br>istream & getline(istream & is, Student & stu)<br>{<br> getline(is, stu.name);<br> return is;<br>}<br><br>// use string version of operator<<()<br>ostream & operator<<(ostream & os, const Student & stu)<br>{<br> os << "Scores for " << stu.name << ":\n";<br> stu.arr_out(os); // use private method for scores<br> return os;<br>}
使用
#include <iostream><br>#include "studentc.h"<br>using std::cin;<br>using std::cout;<br>using std::endl;<br><br>void set(Student & sa, int n);<br><br>const int pupils = 3;<br>const int quizzes = 5;<br><br>int main()<br>{<br> Student ada[pupils] = <br> {Student(quizzes), Student(quizzes), Student(quizzes)};<br><br> int i;<br> for (i = 0; i < pupils; ++i)<br> set(ada[i], quizzes);<br> cout << "\nStudent List:\n";<br> for (i = 0; i < pupils; ++i)<br> cout << ada[i].Name() << endl;<br> cout << "\nResults:";<br> for (i = 0; i < pupils; ++i)<br> {<br> cout << endl << ada[i];<br> cout << "average: " << ada[i].Average() << endl;<br> }<br> cout << "Done.\n";<br><br> // cin.get();<br><br> return 0;<br>}<br><br>void set(Student & sa, int n)<br>{<br> cout << "Please enter the student's name: ";<br> getline(cin, sa);<br> cout << "Please enter " << n << " quiz scores:\n";<br> for (int i = 0; i < n; i++)<br> cin >> sa[i];<br> while (cin.get() != '\n')<br> continue; <br>}
说明
类声明/类定义
重命名
typedef std::valarray<double> ArrayDb;<br>
可以用ArrayDb来替代valarray<double>
构造函数
explicit Student(const std::string & s): name(s), scores() {}<br> explicit Student(int n) : name("Nully"), scores(n) {}
使用explict关闭隐式转换,使编译阶段出现错误优于在运行阶段出现错误
说明:<br>Student stu1="sally"; x<br>Student stu2;<br>stu2=9; x <br>//不可以。<br><br>Student stu1= Student("sally");<br>Stu2 = Student(9); 才可以。
Student(const std::string & s, int n)<br> : name(s), scores(n) {}
scores(n)表示数组的大小为n
Student(const std::string & s, const ArrayDb & a)<br> : name(s), scores(a) {}
scores(a)表示初始化数组为a
Student(const char * str, const double * pd, int n)<br> : name(str), scores(pd, n) {}
scores(pd,n)表示前n个元素初始化为数组pd
成员函数
// private method for scores output<br> std::ostream & arr_out(std::ostream & os) const;
输出成员数据的valarray中的数据。<br>由友元函数operator<<( ) 引用
double Average() const;
计算并返回平均值
const std::string & Name() const;
返回名字
double & operator[](int i);<br> double operator[](int i) const;
不理解为什么两个都可以存在??
第一个可以修改valarray<>数组中的值<br>第二个不可以修改
Student stu1;<br>stu1[0]、stu1[1]、表示各科的成绩。
友元函数
friend std::istream & operator>>(std::istream & is, Student & stu); // 1 word
Student stu2;<br>cin>>stu2;表示输入stu2中的name成员。//只能是一个单词<br>至于valarray<>数组中的元素,可以直接<br>cin>>stu2[n];来直接表示输入
friend std::istream & getline(std::istream & is,Student & stu); // 1 line
Student stu2;<br>getline(cin,stu2);//表示输入一行的字符串给stu2对象中的name成员数据
friend std::ostream & operator<<(std::ostream & os,<br> const Student & stu);
Student stu2;<br>...<br>cout<<stu2;//输出对象的成员数据
使用
建立对象数组,注意,ada[][] 表示的是成绩。
其他说明
初始化顺序
C++紫皮书,整理
使用被包含都对象的接口
例如,需要用到valarray中的sum()函数,<br>可以在声明一个公有函数,用scores中的接口
私有继承
描述关系
也是has-a关系,获得<font color="#381e11">实现,不获得接口</font><br>
特点
基类的公有成员和保护成员将成为派生类的私有成员,<br>基类的私有成员派生类不能直接访问
Student实例(私有继承版本)
总代码
类声明
<div>// studenti.h -- defining a Student class using private inheritance</div><div>#ifndef STUDENTC_H_</div><div>#define STUDENTC_H_</div><div><br></div><div>#include <iostream></div><div>#include <valarray></div><div>#include <string> </div><div>class Student : private std::string, private std::valarray<double></div><div>{ </div><div>private:</div><div> typedef std::valarray<double> ArrayDb;<br><br></div><div> // private method for scores output</div><div> std::ostream & arr_out(std::ostream & os) const;<br><br></div><div>public:</div><div> Student() : std::string("Null Student"), ArrayDb() {}</div><div> explicit Student(const std::string & s)</div><div> : std::string(s), ArrayDb() {}</div><div> explicit Student(int n) : std::string("Nully"), ArrayDb(n) {}</div><div> Student(const std::string & s, int n)</div><div> : std::string(s), ArrayDb(n) {}</div><div> Student(const std::string & s, const ArrayDb & a)</div><div> : std::string(s), ArrayDb(a) {}</div><div> Student(const char * str, const double * pd, int n)</div><div> : std::string(str), ArrayDb(pd, n) {}</div><div> ~Student() {}</div><div> double Average() const;</div><div> double & operator[](int i);</div><div> double operator[](int i) const;</div><div> const std::string & Name() const;<br><br></div><div>// friends</div><div> // input</div><div> friend std::istream & operator>>(std::istream & is,</div><div> Student & stu); // 1 word</div><div> friend std::istream & getline(std::istream & is,</div><div> Student & stu); // 1 line</div><div> // output</div><div> friend std::ostream & operator<<(std::ostream & os,</div><div> const Student & stu);</div><div>};</div><div><br></div><div>#endif</div><div><br></div>
类定义
<div>// studenti.cpp -- Student class using private inheritance</div><div>#include "studenti.h"</div><div>using std::ostream;</div><div>using std::endl;</div><div>using std::istream;</div><div>using std::string;</div><div><br></div><div>// public methods</div><div>double Student::Average() const</div><div>{</div><div> if (ArrayDb::size() > 0)</div><div> return ArrayDb::sum()/ArrayDb::size(); </div><div> else</div><div> return 0;</div><div>}</div><div><br></div><div>const string & Student::Name() const</div><div>{</div><div> return (const string &) *this;</div><div>}</div><div><br></div><div>double & Student::operator[](int i)</div><div>{</div><div> return ArrayDb::operator[](i); // use ArrayDb::operator[]()</div><div>}</div><div><br></div><div>double Student::operator[](int i) const</div><div>{</div><div> return ArrayDb::operator[](i);</div><div>}</div><div><br></div><div>// private method。的金额</div><div>ostream & Student::arr_out(ostream & os) const</div><div>{</div><div> int i;</div><div> int lim = ArrayDb::size();</div><div> if (lim > 0)</div><div> {</div><div> for (i = 0; i < lim; i++)</div><div> {</div><div> os << ArrayDb::operator[](i) << " ";</div><div> if (i % 5 == 4)</div><div> os << endl;</div><div> }</div><div> if (i % 5 != 0)</div><div> os << endl;</div><div> }</div><div> else</div><div> os << " empty array ";</div><div> return os; </div><div>}</div><div><br></div><div>// friends</div><div>// use String version of operator>>()</div><div>istream & operator>>(istream & is, Student & stu)</div><div>{</div><div> is >> (string &)stu;</div><div> return is; </div><div>}</div><div><br></div><div>// use string friend getline(ostream &, const string &)</div><div>istream & getline(istream & is, Student & stu)</div><div>{</div><div> getline(is, (string &)stu);</div><div> return is;</div><div>}</div><div><br></div><div>// use string version of operator<<()</div><div>ostream & operator<<(ostream & os, const Student & stu)</div><div>{</div><div> os << "Scores for " << (const string &) stu << ":\n";</div><div> stu.arr_out(os); // use private method for scores</div><div> return os;</div><div>}</div>
使用
<div>#include <iostream></div><div>#include "studenti.h"</div><div>using std::cin;</div><div>using std::cout;</div><div>using std::endl;</div><div><br></div><div>void set(Student & sa, int n);</div><div><br></div><div>const int pupils = 3;</div><div>const int quizzes = 5;</div><div><br></div><div>int main()</div><div>{</div><div> Student ada[pupils] = </div><div> {Student(quizzes), Student(quizzes), Student(quizzes)};</div><div><br></div><div> int i;</div><div> for (i = 0; i < pupils; i++)</div><div> set(ada[i], quizzes);</div><div> cout << "\nStudent List:\n";</div><div> for (i = 0; i < pupils; ++i)</div><div> cout << ada[i].Name() << endl;</div><div> cout << "\nResults:";</div><div> for (i = 0; i < pupils; i++)</div><div> {</div><div> cout << endl << ada[i];</div><div> cout << "average: " << ada[i].Average() << endl;</div><div> }</div><div> cout << "Done.\n";</div><div> // cin.get();</div><div> return 0;</div><div>}</div><div><br></div><div>void set(Student & sa, int n)</div><div>{</div><div> cout << "Please enter the student's name: ";</div><div> getline(cin, sa);</div><div> cout << "Please enter " << n << " quiz scores:\n";</div><div> for (int i = 0; i < n; i++)</div><div> cin >> sa[i];</div><div> while (cin.get() != '\n')</div><div> continue; </div><div>}</div><div><br></div>
说明
类声明/类定义
构造函数
组合:<br>Student(const std::string & s, const ArrayDb & a)<br> : name(s), scores(a) {}<br>私有继承: <br>Student(const std::string & s, int n) <br> : std::string(s), ArrayDb(n) {}
说明
因为私有继承没有具体名,所以直接调用基类的函数。<br>ArrayDb是std::valarray<double>的别名
成员函数
1<br>(调用基类的方法)
组合关系
double Student::Average() const<br>{<br> if (scores.size() > 0)<br> return scores.sum()/scores.size(); <br> else <br> return 0;<br>}<br>
私有继承
return ArrayDb::sum()/ArrayDb::size();
说明
另外如果派生类中有同名函数(不管参数或者其他是否不同),<br>需要有作用限定域符号。<br>如果没有同名函数,可以不用作用限定域,上其实可以不使用。//??<br>还是因为是私有继承所以要限定域??
2<br>(返回基类的私有数据)
组合关系
string
const string & Student::Name() const<br>{<br> return name;<br>}
arrayDb
double & Student::operator[](int i)<br>{<br> return scores[i]; // use valarray<double>::operator[]()<br>}<br>
私有继承
string
<div>const string & Student::Name() const</div><div>{</div><div> return (const string &) *this;</div><div>}</div>
arrayDb
<div>double & Student::operator[](int i)</div><div>{</div><div> return ArrayDb::operator[](i); // use ArrayDb::operator[]()</div><div>}</div>
说明
return (const string &) *this;表示返回派生类的基类string部分
return ArrayDb::operator[](i); //调用ArrayDb的operator[]函数
友元函数
组合关系
istream & operator>>(istream & is, Student & stu)<br>{<br> is >> stu.name;<br> return is; <br>}
<ul><li>有对象名,所以可以使用通过对象名使用函数。<br></li><li>继承只能通过调用基类的函数,但是友元类不属于类,不能用类名显式地限定函数名。</li><li>友元函数可以访问派生类的私有数据成员,当然也可以访问基类的公有、保护成员<br></li></ul>
私有继承
<div>istream & operator>>(istream & is, Student & stu)</div><div>{</div><div> is >> (string &)stu;</div><div> return is; </div><div>}</div>
os<<( string &)stu;//输出string的name
说明
os<<( string &)stu;将stu转化为string对象引用,<br>进而调用函数operator<<(ostream &,const String &)
使用
和组合差不多
(选择)has-a关系<br>使用包含还是私有继承
一般使用包含来建立has-a关系<br>如果新类的需要访问原有类的保护成员,<br>或需要重新定义虚函数,则应使用继承。
保护继承
特点
基类的公有成员和保护成员将成为派生类的保护成员,<br>基类的私有成员派生类不能直接访问。
与私有继承区别
区别体现在,从派生类中派生另一个类时。
各种继承方式区别
表格
<table style="box-sizing: border-box; width: 946.4px; border-collapse: collapse; border-spacing: 0px; border: 1px solid rgb(238, 238, 238); color: rgb(0, 0, 0); font-family: 'microsoft yahei'; font-size: 14px; line-height: 26px;"><thead style="box-sizing: border-box;"><tr style="box-sizing: border-box;"><th style="box-sizing: border-box; border-color: rgb(238, 238, 238);">特征</th><th style="box-sizing: border-box; border-color: rgb(238, 238, 238);">公有继承</th><th style="box-sizing: border-box; border-color: rgb(238, 238, 238);">保护继承</th><th style="box-sizing: border-box; border-color: rgb(238, 238, 238);">私有继承</th></tr></thead><tbody style="box-sizing: border-box;"><tr style="box-sizing: border-box;"><td style="box-sizing: border-box; padding: 8px; line-height: 20px; vertical-align: top; border: 1px solid rgb(238, 238, 238);">公有成员变成</td><td style="box-sizing: border-box; padding: 8px; line-height: 20px; vertical-align: top; border: 1px solid rgb(238, 238, 238);">派生类的公有成员</td><td style="box-sizing: border-box; padding: 8px; line-height: 20px; vertical-align: top; border: 1px solid rgb(238, 238, 238);">派生类的保护成员</td><td style="box-sizing: border-box; padding: 8px; line-height: 20px; vertical-align: top; border: 1px solid rgb(238, 238, 238);">派生类的私有成员</td></tr><tr style="box-sizing: border-box;"><td style="box-sizing: border-box; padding: 8px; line-height: 20px; vertical-align: top; border: 1px solid rgb(238, 238, 238);">保护成员变成</td><td style="box-sizing: border-box; padding: 8px; line-height: 20px; vertical-align: top; border: 1px solid rgb(238, 238, 238);">派生类的保护成员</td><td style="box-sizing: border-box; padding: 8px; line-height: 20px; vertical-align: top; border: 1px solid rgb(238, 238, 238);">派生类的保护成员</td><td style="box-sizing: border-box; padding: 8px; line-height: 20px; vertical-align: top; border: 1px solid rgb(238, 238, 238);">派生类的私有成员</td></tr><tr style="box-sizing: border-box;"><td style="box-sizing: border-box; padding: 8px; line-height: 20px; vertical-align: top; border: 1px solid rgb(238, 238, 238);">私有成员变成</td><td style="box-sizing: border-box; padding: 8px; line-height: 20px; vertical-align: top; border: 1px solid rgb(238, 238, 238);">只能通过基类接口访问</td><td style="box-sizing: border-box; padding: 8px; line-height: 20px; vertical-align: top; border: 1px solid rgb(238, 238, 238);">只能通过基类接口访问</td><td style="box-sizing: border-box; padding: 8px; line-height: 20px; vertical-align: top; border: 1px solid rgb(238, 238, 238);">只能通过基类接口访问</td></tr><tr style="box-sizing: border-box;"><td style="box-sizing: border-box; padding: 8px; line-height: 20px; vertical-align: top; border: 1px solid rgb(238, 238, 238);">能否隐式向上转换</td><td style="box-sizing: border-box; padding: 8px; line-height: 20px; vertical-align: top; border: 1px solid rgb(238, 238, 238);">是</td><td style="box-sizing: border-box; padding: 8px; line-height: 20px; vertical-align: top; border: 1px solid rgb(238, 238, 238);">是(但只能在派生类中)</td><td style="box-sizing: border-box; padding: 8px; line-height: 20px; vertical-align: top; border: 1px solid rgb(238, 238, 238);">否</td></tr></tbody></table>
说明
<b>私有继承不能隐式向上转换原因:</b><br>(隐式向上转换说明基类的指针或引用指向派生类对象)
可以的话,就相当于调用了基类接口。<br>
为什么不能在派生类中?
在派生类中使用隐式<br>向上转换:<br>
Student::Student(Student & stu)<br>:basestudent(stu)<br>???相当于这样吗?觉得私有继承应该也可以这样做啊
(私有继承、保护继承)<br>使用using重新定义访问权限
问题
使Student能够使用valarray类的sum()方法<br>
方法一
在Student类中声明一个sum()方法
double Student::sum() const<br>{<br> return std::valarray<double>::sum();<br>}
方法二
using声明来指出派生类可以使用特定的基类成员,<br>即使采用的是私有派生。<br>在派生类的公有部分声明
class Student:private std::string,private std::valarrat<double><br>{<br>....<br>public:<br> using std::valarray<double>::sum();<br>}
多重继承(MI)
描述关系
公有MI
is-a关系
私有、保护MI
has-a关系
类声明格式
class singingWaiter:public Waiter, public Singer{ ... };
说明
class singingWaiter:public Waiter, Singer{ ... };<br>//Singer 前没有public,会认为Singer是私有继承
Mi问题(主要)
从两个不同基类继承同名方法
从两个或更多相关基类那里继承同一个类的多个实例
实例//worker0<br>(没有派生singerwaiter)
类声明
<div>// worker0.h -- working classes</div><div>#ifndef WORKER0_H_</div><div>#define WORKER0_H_</div><div><br></div><div>#include <string></div><div><br></div><div>class Worker // an abstract base class</div><div>{</div><div>private:</div><div> std::string fullname;</div><div> long id;</div><div>public:</div><div> Worker() : fullname("no one"), id(0L) {}</div><div> Worker(const std::string & s, long n)</div><div> : fullname(s), id(n) {}</div><div> virtual ~Worker() = 0; // pure virtual destructor</div><div> virtual void Set();</div><div> virtual void Show() const;</div><div>};</div><div><br></div><div>class Waiter : public Worker</div><div>{</div><div>private:</div><div> int panache;</div><div>public:</div><div> Waiter() : Worker(), panache(0) {}</div><div> Waiter(const std::string & s, long n, int p = 0)</div><div> : Worker(s, n), panache(p) {}</div><div> Waiter(const Worker & wk, int p = 0)</div><div> : Worker(wk), panache(p) {}</div><div> void Set();</div><div> void Show() const;</div><div>};</div><div><br></div><div>class Singer : public Worker</div><div>{</div><div>protected:</div><div> enum {other, alto, contralto, soprano,</div><div> bass, baritone, tenor};</div><div> enum {Vtypes = 7};</div><div>private:</div><div> static char *pv[Vtypes]; // string equivs of voice types</div><div> int voice;</div><div>public:</div><div> Singer() : Worker(), voice(other) {}</div><div> Singer(const std::string & s, long n, int v = other)</div><div> : Worker(s, n), voice(v) {}</div><div> Singer(const Worker & wk, int v = other)</div><div> : Worker(wk), voice(v) {}</div><div> void Set();</div><div> void Show() const;</div><div>};</div><div><br></div><div>#endif</div>
类定义
<div>// worker0.cpp -- working class methods</div><div>#include "worker0.h"</div><div>#include <iostream></div><div>using std::cout;</div><div>using std::cin;</div><div>using std::endl;</div><div>// Worker methods</div><div><br></div><div>// must implement virtual destructor, even if pure</div><div>Worker::~Worker() {}</div><div><br></div><div>void Worker::Set()</div><div>{</div><div> cout << "Enter worker's name: ";</div><div> getline(cin, fullname);</div><div> cout << "Enter worker's ID: ";</div><div> cin >> id;</div><div> while (cin.get() != '\n')</div><div> continue;</div><div>}</div><div><br></div><div>void Worker::Show() const</div><div>{</div><div> cout << "Name: " << fullname << "\n";</div><div> cout << "Employee ID: " << id << "\n";</div><div>}</div><div><br></div><div>// Waiter methods</div><div>void Waiter::Set()</div><div>{</div><div> Worker::Set();</div><div> cout << "Enter waiter's panache rating: ";</div><div> cin >> panache;</div><div> while (cin.get() != '\n')</div><div> continue;</div><div>}</div><div><br></div><div>void Waiter::Show() const</div><div>{</div><div> cout << "Category: waiter\n";</div><div> Worker::Show();</div><div> cout << "Panache rating: " << panache << "\n";</div><div>}</div><div><br></div><div>// Singer methods</div><div><br></div><div>char * Singer::pv[] = {"other", "alto", "contralto",</div><div> "soprano", "bass", "baritone", "tenor"};</div><div><br></div><div>void Singer::Set()</div><div>{</div><div> Worker::Set();</div><div> cout << "Enter number for singer's vocal range:\n";</div><div> int i;</div><div> for (i = 0; i < Vtypes; i++)</div><div> {</div><div> cout << i << ": " << pv[i] << " ";</div><div> if ( i % 4 == 3)</div><div> cout << endl;</div><div> }</div><div> if (i % 4 != 0)</div><div> cout << endl;</div><div> while (cin >> voice && (voice < 0 || voice >= Vtypes) )</div><div> cout << "Please enter a value >= 0 and < " << Vtypes << endl;</div><div> while (cin.get() != '\n')</div><div> continue;</div><div>}</div><div><br></div><div>void Singer::Show() const</div><div>{</div><div> cout << "Category: singer\n";</div><div> Worker::Show();</div><div> cout << "Vocal range: " << pv[voice] << endl;</div><div>}</div><div><br></div>
使用
<div>// worktest.cpp -- test worker class hierarchy</div><div>#include <iostream></div><div>#include "worker0.h"</div><div>const int LIM = 4;</div><div>int main()</div><div>{</div><div> Waiter bob("Bob Apple", 314L, 5);</div><div> Singer bev("Beverly Hills", 522L, 3);</div><div> Waiter w_temp;</div><div> Singer s_temp;</div><div><br></div><div> Worker * pw[LIM] = {&bob, &bev, &w_temp, &s_temp};</div><div><br></div><div> int i;</div><div> for (i = 2; i < LIM; i++)</div><div> pw[i]->Set();</div><div> for (i = 0; i < LIM; i++)</div><div> {</div><div> pw[i]->Show();</div><div> std::cout << std::endl;</div><div> }</div><div> // std::cin.get();</div><div> return 0;</div><div>}</div>
说明
构造函数里面,不要直接cin>>,<br>此例中,set()成员函数可以,但千万不要出现在构造函数中。
i%4==3 表示每四个数,加一endl;<br>后if( i%4 !=0 ) cout<<endl;表示如果总输出不是4的倍数,也要输出空行<br>
1 2 3 4<br>5 6 7 8<br>9 10<br>....
如果从waiter、singer <br>上派生出singerwaiter<br>
类声明
class SingerWaiter : public Singer , public Waiter { ... }
问题
有多少个worker?
保留两个Worker副本
SingerWaiter ed;<br>Worker *pw = &ed; // ambiguous,不允许<br>
Worker *pw1=(Waiter *) ed;<br>Worker *pw2=(Waiter *)ed;
哪个方法?
(有多少个worker?)<br>虚基类
解决问题
从两个或更多相关基类那里继承同一个类的多个实例
使SingerWaiter对象只包含Worker对象的一个副本。
虚基类定义
class Woker;<br>class Waiter: virtual public Worker<br>class Singer: virtual public Worker<br>class SingerWaiter: public Waiter, public Singer<br>
疑问<br>(不要看了)
为什么使用术语虚?
与虚函数没有什么联系,引进新关键字会很麻烦,所以“重载”虚关键字
为什么不抛弃将基类声明为虚的这种方式,使虚行为成为多MI的准则<br>(更像问为什么不抛弃不声明为虚的方式)
可能需要基类的多个拷贝
将基类作为虚的要求程序完成额外的工作
有其缺点(。。)
是否存在麻烦?
必须以不同的方式编写一些代码。eg:在worker ,singer前加virtual
新的构造函数规则
问题
单继承
代码
<div>class A{</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>int a;</div><div>public:</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>A(int n = 0) :a(n){}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>....</div><div>};</div><div><br></div><div>class B :public A{</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>int b;</div><div>public:</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>B(int m = 0; int n = 0 ): A(n),b(m){}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>....</div><div>};</div><div><br></div><div>class C :public B{</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>int c;</div><div>public:</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>C(int q = 0,int m = 0,int n = 0):B(m,n),c(q){}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>.....</div><div>};</div>
说明
C-->B(m,n)-->B-->A(n)-->A ,传递性
基类是虚时候
SingerWaiter(const Worker & wk , int p=0 , int v = Singer::other)<br>:Waiter( wk,p),Singer(wk,v){}//flawed
<ul><li>不起作用,因为将通过两种不同的途径(worker 和 singer)将wk传递给Worker对象。<br></li><li>C++基类为虚时,禁止信息通过中间类自动传递给基类,所以上述构造函数将初始化<br></li></ul>成员panache 和 voice ,但wk参数中的信息不会传递给子对象waiter.//只有构造函数才是这样?<br><ul><li>但又必须派生对象之前构造基类对象组件。<br></li></ul>
构造方式
SingingWaiter( const Worker &wk,int p = 0 , int v = Singer::other)<br>:Worker(wk),Waiter(wk,p),Singer(wk,v)
说明
<ul><li>对虚基类,除非只需使用该虚基类的默认构造函数,这种用法<br></li></ul>(直接调用虚基类的构造函数,即使不是直接基类)是合法的也是必须的。<br><ul><li>对非虚基类,这种用法是不正确的。<br></li></ul>
(哪个方法?)
1
问题
Singer 中有show()方法<br>Waiter中有show()方法<br><br>SingerWaiter newhire( "Elise Hawks" , 2005 , 6 , soprano);<br>newhire.Show( );//ambiguous
解决
1
作用域解析运算<br>
newhire.Singer::Show( ) ;<br>newhire.Waiter::Show( ) ;
2
在SingerWaiter中<br>重新定义Show( )<br>//指明使用哪个版本
void SingingWaiter::Show()<br>{<br> Singer::Show();<br>}
2
问题
void SingingWaiter::Show()<br>{<br> Singer::Show();<br> Waiter::Show();<br>}<br>//会调用两次Worker::Show(),信息混乱
<div>void Singer::Show() const</div><div>{</div><div> cout << "Category: singer\n";</div><div> Worker::Show();</div><div> cout << "Vocal range: " << pv[voice] << endl;</div><div>}</div>
<div>void Waiter::Show() const</div><div>{</div><div> cout << "Category: waiter\n";</div><div> Worker::Show();</div><div> cout << "Panache rating: " << panache << "\n";</div><div>}<br></div>
<div>void Worker::Show() const</div><div>{</div><div> cout << "Name: " << fullname << "\n";</div><div> cout << "Employee ID: " << id << "\n";</div><div>}</div>
解决
加一个属于保护,只显示自身<br>(新增)数据的data()方法。<br>//派生类例外,显示两个直接基类数据<br>的data()方法(其实可以不定义吧)
<div>void Worker::Data() const</div><div>{</div><div> cout << "Name: " << fullname << endl;</div><div> cout << "Employee ID: " << id << endl;</div><div>}</div>
子主题
<div>void Waiter::Data() const</div><div>{</div><div> cout << "Panache rating: " << panache << endl;</div><div>}</div>
<div>//public<br>void Waiter::Show() const</div><div>{</div><div> cout << "Category: waiter\n";</div><div> Worker::Data();</div><div> Data();</div><div>}</div>
<div>void Singer::Data() const</div><div>{</div><div> cout << "Vocal range: " << pv[voice] << endl;</div><div>}</div>
<div>//public<br>void Waiter::Show() const</div><div>{</div><div> cout << "Category: waiter\n";</div><div> Worker::Data();</div><div> Data();</div><div>}</div>
<div>void SingingWaiter::Data() const</div><div>{</div><div> Singer::Data();</div><div> Waiter::Data();</div><div>}</div>
<div>//public<br>void Waiter::Show() const</div><div>{</div><div> cout << "Category: waiter\n";</div><div> Worker::Data(); // 可以直接用!!不要忘记了</div><div> Data();</div><div>}</div>
其他
Set()函数也一样,处理方法相同
实例<br>(解决了问题的实例)
类声明
<div>// workermi.h -- working classes with MI</div><div>#ifndef WORKERMI_H_</div><div>#define WORKERMI_H_</div><div><br></div><div>#include <string></div><div><br></div><div>class Worker // an abstract base class</div><div>{</div><div>private:</div><div> std::string fullname;</div><div> long id;</div><div>protected:</div><div> virtual void Data() const;</div><div> virtual void Get();</div><div>public:</div><div> Worker() : fullname("no one"), id(0L) {}</div><div> Worker(const std::string & s, long n)</div><div> : fullname(s), id(n) {}</div><div> virtual ~Worker() = 0; // pure virtual function</div><div> virtual void Set() = 0;</div><div> virtual void Show() const = 0;</div><div>};</div><div><br></div><div>class Waiter : virtual public Worker</div><div>{</div><div>private:</div><div> int panache;</div><div>protected:</div><div> void Data() const;</div><div> void Get();</div><div>public:</div><div> Waiter() : Worker(), panache(0) {}</div><div> Waiter(const std::string & s, long n, int p = 0)</div><div> : Worker(s, n), panache(p) {}</div><div> Waiter(const Worker & wk, int p = 0)</div><div> : Worker(wk), panache(p) {}</div><div> void Set();</div><div> void Show() const;</div><div>};</div><div><br></div><div>class Singer : virtual public Worker</div><div>{</div><div>protected:</div><div>enum {other, alto, contralto, soprano,</div><div> bass, baritone, tenor};</div><div> enum {Vtypes = 7};</div><div> void Data() const;</div><div> void Get();</div><div>private:</div><div> static char *pv[Vtypes]; // string equivs of voice types</div><div> int voice;</div><div>public:</div><div> Singer() : Worker(), voice(other) {}</div><div> Singer(const std::string & s, long n, int v = other)</div><div> : Worker(s, n), voice(v) {}</div><div> Singer(const Worker & wk, int v = other)</div><div> : Worker(wk), voice(v) {}</div><div> void Set();</div><div> void Show() const;</div><div>};</div><div><br></div><div>// multiple inheritance</div><div>class SingingWaiter : public Singer, public Waiter</div><div>{</div><div>protected:</div><div> void Data() const;</div><div> void Get();</div><div>public:</div><div> SingingWaiter() {}</div><div> SingingWaiter(const std::string & s, long n, int p = 0,</div><div> int v = other)</div><div> : Worker(s,n), Waiter(s, n, p), Singer(s, n, v) {}</div><div> SingingWaiter(const Worker & wk, int p = 0, int v = other)</div><div> : Worker(wk), Waiter(wk,p), Singer(wk,v) {}</div><div> SingingWaiter(const Waiter & wt, int v = other)</div><div> : Worker(wt),Waiter(wt), Singer(wt,v) {}</div><div> SingingWaiter(const Singer & wt, int p = 0)</div><div> : Worker(wt),Waiter(wt,p), Singer(wt) {}</div><div> void Set();</div><div> void Show() const; </div><div>};</div><div><br></div><div>#endif</div><div><br></div>
类定义
<div>// workermi.h -- working classes with MI</div><div>#ifndef WORKERMI_H_</div><div>#define WORKERMI_H_</div><div><br></div><div>#include <string></div><div><br></div><div>class Worker // an abstract base class</div><div>{</div><div>private:</div><div> std::string fullname;</div><div> long id;</div><div>protected:</div><div> virtual void Data() const;</div><div> virtual void Get();</div><div>public:</div><div> Worker() : fullname("no one"), id(0L) {}</div><div> Worker(const std::string & s, long n)</div><div> : fullname(s), id(n) {}</div><div> virtual ~Worker() = 0; // pure virtual function</div><div> virtual void Set() = 0;</div><div> virtual void Show() const = 0;</div><div>};</div><div><br></div><div>class Waiter : virtual public Worker</div><div>{</div><div>private:</div><div> int panache;</div><div>protected:</div><div> void Data() const;</div><div> void Get();</div><div>public:</div><div> Waiter() : Worker(), panache(0) {}</div><div> Waiter(const std::string & s, long n, int p = 0)</div><div> : Worker(s, n), panache(p) {}</div><div> Waiter(const Worker & wk, int p = 0)</div><div> : Worker(wk), panache(p) {}</div><div> void Set();</div><div> void Show() const;</div><div>};</div><div><br></div><div>class Singer : virtual public Worker</div><div>{</div><div>protected:</div><div>enum {other, alto, contralto, soprano,</div><div> bass, baritone, tenor};</div><div> enum {Vtypes = 7};</div><div> void Data() const;</div><div> void Get();</div><div>private:</div><div> static char *pv[Vtypes]; // string equivs of voice types</div><div> int voice;</div><div>public:</div><div> Singer() : Worker(), voice(other) {}</div><div> Singer(const std::string & s, long n, int v = other)</div><div> : Worker(s, n), voice(v) {}</div><div> Singer(const Worker & wk, int v = other)</div><div> : Worker(wk), voice(v) {}</div><div> void Set();</div><div> void Show() const;</div><div>};</div><div><br></div><div>// multiple inheritance</div><div>class SingingWaiter : public Singer, public Waiter</div><div>{</div><div>protected:</div><div> void Data() const;</div><div> void Get();</div><div>public:</div><div> SingingWaiter() {}</div><div> SingingWaiter(const std::string & s, long n, int p = 0,</div><div> int v = other)</div><div> : Worker(s,n), Waiter(s, n, p), Singer(s, n, v) {}</div><div> SingingWaiter(const Worker & wk, int p = 0, int v = other)</div><div> : Worker(wk), Waiter(wk,p), Singer(wk,v) {}</div><div> SingingWaiter(const Waiter & wt, int v = other)</div><div> : Worker(wt),Waiter(wt), Singer(wt,v) {}</div><div> SingingWaiter(const Singer & wt, int p = 0)</div><div> : Worker(wt),Waiter(wt,p), Singer(wt) {}</div><div> void Set();</div><div> void Show() const; </div><div>};</div><div><br></div><div>#endif</div><div><br></div>
使用
代码
<div>// workmi.cpp -- multiple inheritance</div><div>// compile with workermi.cpp</div><div>#include <iostream></div><div>#include <cstring></div><div>#include "workermi.h"</div><div>const int SIZE = 5;</div><div><br></div><div>int main()</div><div>{</div><div> using std::cin;</div><div> using std::cout;</div><div> using std::endl;</div><div> using std::strchr;</div><div><br></div><div> Worker * lolas[SIZE];</div><div><br></div><div> int ct;</div><div> for (ct = 0; ct < SIZE; ct++)</div><div> {</div><div> char choice;</div><div> cout << "Enter the employee category:\n"</div><div> << "w: waiter s: singer "</div><div> << "t: singing waiter q: quit\n";</div><div> cin >> choice;</div><div> while (strchr("wstq", choice) == NULL)</div><div> {</div><div> cout << "Please enter a w, s, t, or q: ";</div><div> cin >> choice;</div><div> }</div><div> if (choice == 'q')</div><div> break;</div><div> switch(choice)</div><div> {</div><div> case 'w': lolas[ct] = new Waiter;</div><div> break;</div><div> case 's': lolas[ct] = new Singer;</div><div> break;</div><div> case 't': lolas[ct] = new SingingWaiter;</div><div> break;</div><div> }</div><div> cin.get();</div><div> lolas[ct]->Set();</div><div> }</div><div><br></div><div> cout << "\nHere is your staff:\n";</div><div> int i;</div><div> for (i = 0; i < ct; i++)</div><div> {</div><div> cout << endl;</div><div> lolas[i]->Show();</div><div> }</div><div> for (i = 0; i < ct; i++)</div><div> delete lolas[i];</div><div> cout << "Bye.\n";</div><div> // cin.get();</div><div> // cin.get();</div><div> return 0; </div><div>}</div><div><br></div>
说明
while (strchr("wstq", choice) == NULL)<br>//返回choice 在字符串"wstq"中第一次出现的位置
case 'w': 记住要单引号
Mi的其它问题
混合使用虚基类<br>和非虚基类
假设B被用作C和D的虚基类,<br>B被用作X和Y的非虚基类,<br>类M,从C,D,X,Y中派生而来,<br>问:洋浦多少个B类子对象?
3个,<br>类M从虚派生祖先(即类C和D)那里共继承一个B类子对象<br>并从每一个非虚派生祖先(即类X和Y)分别继承了一个B类子对象
虚基类和支配<br>(二义性问题)
问题
不是虚基类
<div>class B</div><div>{</div><div>public:</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>short q();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>... </div><div>};</div><div><br></div><div>class C:public B</div><div>{</div><div>public:</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>long q();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>....</div><div>};</div><div><br></div><div>class F:public B</div><div>{</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>...</div><div>};</div>
F a;<br>a.q();//ambiguous
虚基类
<div>class B</div><div>{</div><div>public:</div><div><span class="Apple-tab-span" style="white-space: pre;"> </span>short q();</div><div><span class="Apple-tab-span" style="white-space: pre;"> </span>... </div><div>};</div><div><br></div><div>class C:virtual public B</div><div>{</div><div>public:</div><div><span class="Apple-tab-span" style="white-space: pre;"> </span>long q();</div><div><span class="Apple-tab-span" style="white-space: pre;"> </span>....</div><div>};</div><div><br></div><div>class F:public B</div><div>{</div><div><span class="Apple-tab-span" style="white-space: pre;"> </span>...</div><div>};</div>
F a;<br>a.q();//valid<br><br>C中的q()优先于B中的q();
说明
使用虚基类时,如果某个名称优先于其他所有名称,名称<br>不会产生二义性。
虚二义性规则与访问规则无关
<div>class B</div><div>{</div><div>public:</div><div><span class="Apple-tab-span" style="white-space: pre;"> </span>short q();</div><div><span class="Apple-tab-span" style="white-space: pre;"> </span>... </div><div>};</div><div><br></div><div>class C:virtual public B</div><div>{</div><div>private://变为私有</div><div><span class="Apple-tab-span" style="white-space: pre;"> </span>long q();</div><div><span class="Apple-tab-span" style="white-space: pre;"> </span>....</div><div>};</div><div><br></div><div>class F:public B</div><div>{</div><div><span class="Apple-tab-span" style="white-space: pre;"> </span>...</div><div>};</div>
不带作用域解析运算符的q() 在F类中或类外都表示为B::q()<br>F a;<br>a.q();//相当于访问了不可访问的q(),所以是不行的。<br>
类模板
作用
提供参数化类型,即能够将类型名作为参数传递给接收方来建立类或函数。
定义、使用
类声明
代码
原来
<div>typedef unsigned long Item;<br>class Stack<br></div><div>{</div><div>private:</div><div> enum {MAX = 10}; // constant specific to class</div><div> Item items[MAX]; // holds stack items</div><div> int top; // index for top stack item</div><div>public:</div><div> Stack();</div><div> bool isempty() const;</div><div> bool isfull() const;</div><div> bool push(const Item & item); // add item to stack</div><div> bool pop(Item & item); // pop top into item</div><div>};</div>
现在
<div>template <class Type></div><div>class Stack</div><div>{</div><div>private:</div><div> enum {MAX = 10}; // constant specific to class</div><div> Type items[MAX]; // holds stack items</div><div> int top; // index for top stack item</div><div>public:</div><div> Stack();</div><div> bool isempty();</div><div> bool isfull();</div><div> bool push(const Type & item); // add item to stack</div><div> bool pop(Type & item); // pop top into item</div><div>};</div><div><br></div>
说明
template<class Type><br>class Stack{<br>.....<br>};
要以template<..>开头,可以把class 看做是变量的类型名,该变量接收类型作为其值.<br>
class可用typename 代替
Type可以使用自己的泛型名代替,一般用T,Type
Item items[MAX](原来)——(变成)Type items[Max]<br>其他函数
对于Stack来说,意味着应将声明中所用typedef标识符Item<br>替换成Type
类定义
代码
<div>template <class Type></div><div>Stack<Type>::Stack()</div><div>{</div><div> top = 0;</div><div>}</div><div><br></div><div>template <class Type></div><div>bool Stack<Type>::isempty()</div><div>{</div><div> return top == 0;</div><div>}</div><div><br></div><div>template <class Type></div><div>bool Stack<Type>::isfull()</div><div>{</div><div> return top == MAX;</div><div>}</div><div><br></div><div>template <class Type></div><div>bool Stack<Type>::push(const Type & item)</div><div>{</div><div> if (top < MAX)</div><div> {</div><div> items[top++] = item;</div><div> return true;</div><div> }</div><div> else</div><div> return false;</div><div>}</div><div><br></div><div>template <class Type></div><div>bool Stack<Type>::pop(Type & item)</div><div>{</div><div> if (top > 0)</div><div> {</div><div> item = items[--top];</div><div> return true;</div><div> }</div><div> else</div><div> return false; </div><div>}</div>
说明
bool Stack::push( const Item &item)<br>{<br>....<br>}
//改为<br>template<class Type><br>bool Stack<Type>::push(const Type & item)<br>{<br>.....<br>}
template<class Type>前缀<br>Stack<Type>限定符
如果在类声明中定义了方法(内联定义),可以省略模板前缀和类限定符
模板的具体实现——如用来处理string对象的栈类称为实例化或具体化
模板不是函数,不能单独编译。一般将所用模板信息放在一个头文件中
使用模板类
代码
<div>// stacktem.cpp -- testing the template stack class</div><div>#include <iostream></div><div>#include <string></div><div>#include <cctype></div><div>#include "stacktp.h"</div><div>using std::cin;</div><div>using std::cout;</div><div><br></div><div>int main()</div><div>{</div><div> Stack<std::string> st; // create an empty stack</div><div> char ch;</div><div> std::string po;</div><div> cout << "Please enter A to add a purchase order,\n"</div><div> << "P to process a PO, or Q to quit.\n";</div><div> while (cin >> ch && std::toupper(ch) != 'Q')</div><div> {</div><div> while (cin.get() != '\n')</div><div> continue;</div><div> if (!std::isalpha(ch))</div><div> {</div><div> cout << '\a';</div><div> continue;</div><div> }</div><div> switch(ch)</div><div> {</div><div> case 'A':</div><div> case 'a': cout << "Enter a PO number to add: ";</div><div> cin >> po;</div><div> if (st.isfull())</div><div> cout << "stack already full\n";</div><div> else</div><div> st.push(po);</div><div> break;</div><div> case 'P':</div><div> case 'p': if (st.isempty())</div><div> cout << "stack already empty\n";</div><div> else {</div><div> st.pop(po);</div><div> cout << "PO #" << po << " popped\n";</div><div> break;</div><div> }</div><div> }</div><div> cout << "Please enter A to add a purchase order,\n"</div><div> << "P to process a PO, or Q to quit.\n";</div><div> }</div><div> cout << "Bye\n";</div><div> // cin.get();</div><div> // cin.get();</div><div> return 0; </div><div>}</div><div><br></div>
原理
仅在程序包含模板不能生成模板类,必须请求实例化。
Stack<int> kernels;<br>Stack<string> colonels;<br>看到上述声明,编译器按Stack<Type>模板生成两个独立的类声明和两组独立的类方法。<br>Stack<int>使用Int替换模板中所用的Type
说明
与函数模板不同,类模板必须显式地提供所需的类型。
指针栈<br>(小难点)
应用
功能
某人把一车文件交给Plodson,如果Plodson的收取篮(in-basket)是空的,他将取出车中最上面的文件夹,<br>将其放入收取篮;如果收取篮是满的,plodson将取出篮中最上面的文件,对它进行处理,然后放入发出篮<br>(outbasket);如果收取篮既不是空,也不是满,plodson可能取出篮中最上面的文件进行处理,也可能取出<br>车中下一个文件,放在收取篮中。
代码
头文件
<div>// stcktp1.h -- modified Stack template</div><div>#ifndef STCKTP1_H_</div><div>#define STCKTP1_H_</div><div><br></div><div>template <class Type></div><div>class Stack</div><div>{</div><div>private:</div><div> enum {SIZE = 10}; // default size</div><div> int stacksize;</div><div> Type * items; // holds stack items</div><div> int top; // index for top stack item</div><div>public:</div><div> explicit Stack(int ss = SIZE);</div><div> Stack(const Stack & st);</div><div> ~Stack() { delete [] items; }</div><div> bool isempty() { return top == 0; }</div><div> bool isfull() { return top == stacksize; }</div><div> bool push(const Type & item); // add item to stack</div><div> bool pop(Type & item); // pop top into item</div><div> Stack & operator=(const Stack & st);</div><div>};</div><div><br></div><div>template <class Type></div><div>Stack<Type>::Stack(int ss) : stacksize(ss), top(0)</div><div>{</div><div> items = new Type [stacksize];</div><div>}</div><div><br></div><div>template <class Type></div><div>Stack<Type>::Stack(const Stack & st)</div><div>{</div><div> stacksize = st.stacksize;</div><div> top = st.top;</div><div> items = new Type [stacksize];</div><div> for (int i = 0; i < top; i++)</div><div> items[i] = st.items[i];</div><div>}</div><div><br></div><div>template <class Type></div><div>bool Stack<Type>::push(const Type & item)</div><div>{</div><div> if (top < stacksize)</div><div> {</div><div> items[top++] = item;</div><div> return true;</div><div> }</div><div> else</div><div> return false;</div><div>}</div><div><br></div><div>template <class Type></div><div>bool Stack<Type>::pop(Type & item)</div><div>{</div><div> if (top > 0)</div><div> {</div><div> item = items[--top];</div><div> return true;</div><div> }</div><div> else</div><div> return false;</div><div>}</div><div><br></div><div>template <class Type></div><div>Stack<Type> & Stack<Type>::operator=(const Stack<Type> & st)</div><div>{</div><div> if (this == &st)</div><div> return *this;</div><div> delete [] items;</div><div> stacksize = st.stacksize;</div><div> top = st.top;</div><div> items = new Type [stacksize];</div><div> for (int i = 0; i < top; i++)</div><div> items[i] = st.items[i];</div><div> return *this; </div><div>}</div><div><br></div><div>#endif</div><div><br></div>
使用
<div>// stkoptr1.cpp -- testing stack of pointers</div><div>#include <iostream></div><div>#include <cstdlib> // for rand(), srand()</div><div>#include <ctime> // for time()</div><div>#include "stcktp1.h"</div><div>const int Num = 10;</div><div>int main()</div><div>{</div><div> std::srand(std::time(0)); // randomize rand()</div><div> std::cout << "Please enter stack size: ";</div><div> int stacksize;</div><div> std::cin >> stacksize;</div><div>// create an empty stack with stacksize slots</div><div> Stack<const char *> st(stacksize); </div><div><br></div><div>// in basket</div><div> const char * in[Num] = {</div><div> " 1: Hank Gilgamesh", " 2: Kiki Ishtar",</div><div> " 3: Betty Rocker", " 4: Ian Flagranti",</div><div> " 5: Wolfgang Kibble", " 6: Portia Koop",</div><div> " 7: Joy Almondo", " 8: Xaverie Paprika",</div><div> " 9: Juan Moore", "10: Misha Mache"</div><div> };</div><div> // out basket</div><div> const char * out[Num];</div><div><br></div><div> int processed = 0;</div><div> int nextin = 0;</div><div> while (processed < Num)</div><div> {</div><div> if (st.isempty())</div><div> st.push(in[nextin++]);</div><div> else if (st.isfull())</div><div> st.pop(out[processed++]);</div><div> else if (std::rand() % 2 && nextin < Num) // 50-50 chance</div><div> st.push(in[nextin++]);</div><div> else</div><div> st.pop(out[processed++]);</div><div> }</div><div> for (int i = 0; i < Num; i++)</div><div> std::cout << out[i] << std::endl;</div><div><br></div><div> std::cout << "Bye\n";</div><div> // std::cin.get();</div><div> // std::cin.get();</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>return 0; </div><div>}</div><div><br></div>
说明
Type items[MAX]改为Type * items 是想让栈的大小可变化,<br>因此也新增了一个数据成员stacksize
Type *items<br>....<br>items = new Type[stacksize];//items 是指向数组的指针,items[]也可以照常使用
items = new char *[stacksize]<br>表示数组是指向char*的指针数组,
函数的参数里面。<br>指向指针的引用<br>char *&
http://blog.csdn.net/acs713/article/details/12508049
特殊性
(1)指向指针的引用,不仅改变了指针所指的对象,也改变了指针本身。
(2)指向指针的引用,可以实现对传递给形参的实参数值的交换。即指向指针的引用可以修改指针的值,在参数传递时是传址。
把字符串压入栈实际上是把字符串的地址压入到栈中。<br>从栈中弹出字符串是把地址值复制到out数组中。
数组模板示例<br>和非类型的参数
允许指定数组大小<br>的简单数组模板
方法1
在类中使用动态数组和构造函数参数来提供元素数目,如上的stack
方法2
使用模板参数来提供常规数组大小
方法2代码
<div>//arraytp.h -- Array Template</div><div>#ifndef ARRAYTP_H_</div><div>#define ARRAYTP_H_</div><div><br></div><div>#include <iostream></div><div>#include <cstdlib></div><div><br></div><div>template <class T, int n></div><div>class ArrayTP</div><div>{</div><div>private:</div><div> T ar[n];</div><div>public:</div><div> ArrayTP() {};</div><div> explicit ArrayTP(const T & v);</div><div> virtual T & operator[](int i);</div><div> virtual T operator[](int i) const;</div><div>};</div><div><br></div><div>template <class T, int n></div><div>ArrayTP<T,n>::ArrayTP(const T & v)</div><div>{</div><div> for (int i = 0; i < n; i++)</div><div> ar[i] = v; //把前n个数赋值为数值v;</div><div>}</div><div><br></div><div>template <class T, int n></div><div>T & ArrayTP<T,n>::operator[](int i)</div><div>{</div><div> if (i < 0 || i >= n)</div><div> {</div><div> std::cerr << "Error in array limits: " << i</div><div> << " is out of range\n";</div><div> std::exit(EXIT_FAILURE);</div><div> }</div><div> return ar[i];</div><div>}</div><div><br></div><div>template <class T, int n></div><div>T ArrayTP<T,n>::operator[](int i) const</div><div>{</div><div> if (i < 0 || i >= n)</div><div> {</div><div> std::cerr << "Error in array limits: " << i</div><div> << " is out of range\n";</div><div> std::exit(EXIT_FAILURE);</div><div> }</div><div> return ar[i]; </div><div>}</div><div><br></div><div>#endif</div><div><br></div>
说明
template<class T , int n>
T ——类型参数
n——非类型参数/表达式参数//int n, n指明了类型
表达式参数限制
表达式参数可以是整型、枚举、引用或者指针。<br>double m ,即template<class T ,double m>是不合法的。<br>但double *rm,double *pm是合法的
模板代码不能修改参数的值,也不能使用参数的地址,所用ArrayTP中,<br>n++,&n是非法的。<br>实例化模板时(eg: ArrayTP<double,12> eggweights),表达式参数<br>的值必须是常量表达式。//不可以是变量?
与方法一对比
好处
构造函数方法(方法一)使用的是通过new 和delete管理的堆内存,表达式参数方法使用<br>的是为自动变量维护的内存栈,执行速度快
坏处
每种数组大小都声明自己的模板
//下列生成两个独立的类声明<br>ArrayTP<double , 12>eggweights;<br>ArrayTP<double , 13>donuts;
//下面的声明只生成一个类声明<br>Stack<int>eggs(12);<br>Stack<int>dunkers(13);
构造函数方法(方法2)更通用,它可以将一种尺寸的数组赋给另一种尺寸的数组,<br>也允许改变数组的大小。
<div> virtual T & operator[](int i);——*1</div><div> virtual T operator[](int i) const;——*2<br> //区别?</div>
第一个返回的ar[i]可以作为左值,可以修改ar[i](虽然是私有成员)的内容。(因为返回的是a[i]的引用)
模板的多功能性
模板的用法
用作基类
template<typename T><br>class Array{<br>private:<br> T entry;<br> .....<br>};
template<typename Type><br>clsee GrowArray:public Array<Type>{...};
!!!注意写法
组件类
template<typename TP><br>class Stack<br>{<br> Array<Tp>ar;<br> ......<br>}
用作其他模板<br>的类型参数
Array< Stack<int> >asi;<br>//下详细
C++98要求至少要用一个空白字符将两个>分开以区分>>,<br>C++11不要求这样做
递归使用模板
ArrayTP< ArrayTP<int,5> , 10 > twodee;
含义
twodee是包含10个元素的数组,其中每个元素都是一个包含<br>5个int元素的数组。
等价于int twodee[10][5]
使用
可直接用twodee[i][j]表示...
代码
代码
<div>// twod.cpp -- making a 2-d array</div><div>#include <iostream></div><div>#include "arraytp.h"</div><div>int main(void)</div><div>{</div><div> using std::cout;</div><div> using std::endl;</div><div> ArrayTP<int, 10> sums;</div><div> ArrayTP<double, 10> aves;</div><div> ArrayTP< ArrayTP<int,5>, 10> twodee;</div><div> </div><div> </div><div> int i, j;</div><div> <br>//录入数据</div><div> for (i = 0; i < 10; i++)</div><div> {</div><div> sums[i] = 0;</div><div> for (j = 0; j < 5; j++)</div><div> {</div><div> twodee[i][j] = (i + 1) * (j + 1);</div><div> sums[i] += twodee[i][j];</div><div> }</div><div> aves[i] = (double) sums[i] / 10;</div><div> }<br>//输出数据</div><div> for (i = 0; i < 10; i++)</div><div> {</div><div> for (j = 0; j < 5; j++)</div><div> {</div><div> cout.width(2);</div><div> cout << twodee[i][j] << ' ';</div><div> }</div><div> cout << ": sum = ";</div><div> cout.width(3);</div><div> cout << sums[i] << ", average = " << aves[i] << endl;</div><div> }</div><div> </div><div> cout << "Done.\n";</div><div> // std::cin.get();</div><div> return 0;</div><div>}</div><div><br></div>
结果
<div> 1 2 3 4 5 : sum = 15, average = 1.5</div><div> 2 4 6 8 10 : sum = 30, average = 3</div><div> 3 6 9 12 15 : sum = 45, average = 4.5</div><div> 4 8 12 16 20 : sum = 60, average = 6</div><div> 5 10 15 20 25 : sum = 75, average = 7.5</div><div> 6 12 18 24 30 : sum = 90, average = 9</div><div> 7 14 21 28 35 : sum = 105, average = 10.5</div><div> 8 16 24 32 40 : sum = 120, average = 12</div><div> 9 18 27 36 45 : sum = 135, average = 13.5</div><div>10 20 30 40 50 : sum = 150, average = 15</div><div>Done.</div>
说明
使用多个类型参数
template<class T1 , class T2><br>class pair{<br>....<br>};
代码
<div>// pairs.cpp -- defining and using a Pair template</div><div>#include <iostream></div><div>#include <string></div><div>template <class T1, class T2></div><div>class Pair</div><div>{</div><div>private:</div><div> T1 a;</div><div> T2 b;</div><div>public:</div><div> T1 & first();</div><div> T2 & second();</div><div> T1 first() const { return a; }</div><div> T2 second() const { return b; } //这四个函数的区别注意,一个返回原本的同一个数,</div><div> //所以调用的函数可以作为左值修改返回的数。另一个返回临时对象</div><div> </div><div> Pair(const T1 & aval, const T2 & bval) : a(aval), b(bval) { }</div><div> Pair() {}</div><div>};</div><div><br></div><div>template<class T1, class T2></div><div>T1 & Pair<T1,T2>::first()</div><div>{</div><div> return a;</div><div>}</div><div>template<class T1, class T2></div><div>T2 & Pair<T1,T2>::second()</div><div>{</div><div> return b;</div><div>}</div><div><br></div><div>int main()</div><div>{</div><div> using std::cout;</div><div> using std::endl;</div><div> using std::string;</div><div> Pair<string, int> ratings[4] =</div><div> {</div><div> Pair<string, int>("The Purpled Duck", 5),</div><div> Pair<string, int>("Jaquie's Frisco Al Fresco", 4),</div><div> Pair<string, int>("Cafe Souffle", 5),</div><div> Pair<string, int>("Bertie's Eats", 3)</div><div> };</div><div><br></div><div> int joints = sizeof(ratings) / sizeof (Pair<string, int>); // <font color="#16884a">其实=4</font></div><div> cout << "Rating:\t Eatery\n";</div><div> for (int i = 0; i < joints; i++)</div><div> cout << ratings[i].second() << ":\t "</div><div> << ratings[i].first() << endl;</div><div> cout << "Oops! Revised rating:\n";</div><div> ratings[3].first() = "Bertie's Fab Eats";</div><div> ratings[3].second() = 6;</div><div> cout << ratings[3].second() << ":\t "</div><div> << ratings[3].first() << endl;</div><div> // std::cin.get();</div><div> return 0;</div><div>}</div><div><br></div>
默认类型模板参数
template<class T1, clas T2 = int > class Topo{....};<br><br>Topo<doubledouble,double>m1;<br>Topo<double>m2;//省略T2值,编译器将使用int<br>
说明
可以为类模板类型提供默认值,不能为函数模板参数提供默认值。<br>但都可以为非类型参数提供默认值。
模板的具体化
隐式实例化
ArrayTP<int,100> stuff;
说明
根据所需类型,编译器使用通用模板所提供的处方生成具体的类定义
ArrayTP<double,30> *pt;// 不会生成类的隐式实例化 <br>pt = new ArrayYP<double , 30>;//生成具体的类定义
编译器在需要对象之前,不会生成类的隐式实例化
显式实例化
template class ArrayTP<string,100>;
说明
声明必须位于模板定义所在的名称空间中。(一般需要加名称空间,在哪里加?)
虽然没有创建或提及类对象,编译器也将生成类声明(包括方法定义)
显式具体化<br>(整个模板类)
作用
特定类型(替换模板泛型)的定义
例如,模板
tempalate<typename T><br>class SortedArray{<br>....<br>};
如果T是const char * 类型时,成员函数很多需要改动,需要重新定义一个关于<br>接受const char*类型的类。
格式
template<><br>class SortedArray<font color="#c41230"><const char *></font>{<br>...<br>};
说明
SortedArray<const char *> dates;//使用具体模板<br>当具体模板和通用模板都与实例化请求匹配,编译器使用具体化的版本
早期的编译器格式为<br>class SortedArray<const char *><br>//没有template<>
(模板类中的成员函数具体化)
好像没有?那需要怎么办?只是某个函数不一样,其他不需要改怎么办?
部分具体化
1
作用
类型参数之1指定具体类型
例如,模板
template<class T1,chass T2><br>class Pair{<br>...<br>};
格式
template<class T1><br>class Pair<T1,int>{<br>....<br>}<br>//部分实例化
template<><br>class Pair<int ,int>{<br>...<br>};
说明
多个模板可选择时,编译器将使用具体化程度最高的模板<br>Pair<double,double>p1;//use general Pair template;<br>Pair<double,int>//use Pair<T1,int>;<br>Pair<int,int>//use Pair<int,int>;
2
作用
为指针提供特殊版本来部分具体化现有模板
格式
template<class T><br>class Feeb{ .... };<br><br>template<class T*><br>class Feeb{ ... };<br>
说明
Feeb<char> fb1;<br>Feeb<char *> fb2; // use Feeb T*;
成员模板
内容
1.模板类将另一个模板类作为其成员
2.模板类将模板函数作为其成员
代码
<div>template <typename T></div><div>class beta</div><div>{</div><div>private:</div><div> template <typename V> // nested template class member</div><div> class hold</div><div> {</div><div> private:</div><div> V val;</div><div> public:</div><div> hold(V v = 0) : val(v) {}</div><div> void show() const { cout << val << endl; }</div><div> V Value() const { return val; }</div><div> };</div><div> hold<T> q; // template object</div><div> hold<int> n; // template object</div><div>public:</div><div> beta( T t, int i) : q(t), n(i) {}</div><div> template<typename U> // template method</div><div> U blab(U u, T t) { return (n.Value() + q.Value()) * u / t; }</div><div> void Show() const { q.show(); n.show();}</div><div>};</div><div><br></div><div>int main()</div><div>{</div><div> beta<double> guy(3.5, 3);</div><div> cout << "T was set to double\n";</div><div> guy.Show();</div><div> cout << "V was set to T, which is double, then V was set to int\n";</div><div> cout << guy.blab(10, 2.3) << endl;</div><div> cout << "U was set to int\n";</div><div> cout << guy.blab(10.0, 2.3) << endl;</div><div> cout << "U was set to double\n";</div><div> cout << "Done\n";</div><div> // std::cin.get();</div><div> return 0; </div><div>}</div>
结果
<div>T was set to double</div><div>3.5</div><div>3</div><div>V was set to T, which is double, then V was set to int</div><div>28</div><div>U was set to int</div><div>28.2609</div><div>U was set to double</div><div>Done</div><div>Press any key to continue</div><div><br></div>
说明
1.
在类内声明hold类方法
格式
上代码
说明
deta类中,可以直接用hold类中的公有接口,私有接口不可用。
在类外声明hold类方法
格式
deta中
template<typename T><br>class deta{<br>...<br>private:<br> <font color="#c41230">template<typename V><br> class hold;</font><br>.....<br>}
类外声明
template<typename T><br> template<typename V><br> class <font color="#c41230">beta<T></font>::hold<br> {.....};
那hold的成员函数也在外定义的话怎么办?
template<typename T><br> template<typename V><br> void beta<T>::hold<V>::show() const<br> {.....}//???
说明
有些编译器不支持类外面定义
hold是类的成员,所以要通过使用作用域解析运算符来完成
2.
在类外定义Ublab方法
格式
deta中
template<ctypename T><br>class deta{<br>...<br>public:<br> template<template U><br> U blab( U u , T t);<br>};
类外定义
template<template T><br> template<template U><br> U beta<T>::blab(U u, T t)<br> {<br> ......<br> }
说明
blab中,第二个参数由T决定,第一个参数U根据其具体情况决定<br>eg:<br> cout << guy.blab(10, 2.3) << endl; U被设置为int;<br>cout<<guy.blab(10.0 , 2.3)<<endl; U被设置为诶double;<br>
如果<br>guy.blab( 10, 3 ) //会根据函数原型规则把3转换为double 类型
模板用作参数
代码
<div>// tempparm.cpp ?templates as parameters</div><div>#include <iostream></div><div>#include "stacktp.h"</div><div><br></div><div>template <template <typename T> class Thing></div><div>class Crab</div><div>{</div><div>private:</div><div> Thing<int> s1;</div><div> Thing<double> s2;</div><div>public:</div><div> Crab() {};</div><div> // assumes the thing class has push() and pop() members</div><div> bool push(int a, double x) { return s1.push(a) && s2.push(x); }</div><div> bool pop(int & a, double & x){ return s1.pop(a) && s2.pop(x); }</div><div>};</div><div> </div><div>int main()</div><div>{</div><div> using std::cout;</div><div> using std::cin;</div><div> using std::endl;</div><div> Crab<Stack> nebula;</div><div>// Stack must match template <typename T> class thing </div><div> int ni;</div><div> double nb;</div><div> cout << "Enter int double pairs, such as 4 3.5 (0 0 to end):\n";</div><div> while (cin>> ni >> nb && ni > 0 && nb > 0)</div><div> {</div><div> if (!nebula.push(ni, nb))</div><div> break;</div><div> }</div><div> </div><div> while (nebula.pop(ni, nb))</div><div> cout << ni << ", " << nb << endl;</div><div> cout << "Done.\n";</div><div> // cin.get();</div><div> // cin.get();</div><div> return 0; </div><div>}</div><div><br></div>
结果
<div>Enter int double pairs, such as 4 3.5 (0 0 to end):</div><div><b>50 22.48</b></div><div><b>25 33.87</b></div><div><b>60 19.12</b></div><div><b>0 0//(自己输入的)</b></div><div>60, 19.12</div><div>25, 33.87</div><div>50, 22.48</div><div>Done.</div>
作用<br>(应用)<br>一般用于实现STL
在Crab中<br>Thing<int>s1;<br>Thing<double>s2;<br>为其私有数据成员。<br>
格式
类声明
template<template<typename T> class Thing><br>class Crab{<br>private:<br> Thing<int>s1;<br> Thing<double>s2;<br> .....<br>};
说明
template<typename T> 是类型,Thing是参数<br>//<br>template<typename T>——typename/class<br>Thing ——Type/T
main中,Crab<Stack> nebula;用Stack<int> s1,代替Thing <int> s1
main中,若有Crab<king> legs;<br>则king一定要是类模板;与Thing匹配,即King要有以下定义<br>template<typename T><br>class King{ ... };
模板类和友元
非模板友元
含义
函数本身不是模板,有时会使用一个模板参数(或者不使用)
情形
1
格式
//类声明<br>template<typename T><br>class HasFirend{<br>public:<br> friend void counts()<br> ......<br>}
//类定义<br>void counts()<br>{<br>....<br>};
问题
count对象不通过对象调用,没有对象<br>参数,如何访问Hasfirend对象?
<ol><li>可以访问全局对象<br></li></ol>
??体现
2. 可以使用全局指针访问非全局对象<br>
??体现
3. 可以创建自己的对象
??体现
4. 可以访问独立于对象的模板类的静态数据成员(应用用的是这种)
第4点的应用
代码
//类声明中<br>...<br>class HasFriend{<br>......<br>static int ct;<br>.......<br><br>friend void counts();<br><br>.....<br>};
//类定义中<br>void couts()<br>{<br> cout<<“Int count”<<HasFriend<int>::ct<<";";<br> cout<<"double count"<<HasFriend<double>::ct<<";";
说明
ct为静态数据成员,意味类的每一个特定的具体化都有自己的静态成员。<br>
cout()是<font color="#c41230">所用HasFriend具体化</font>得友元,每个HasFriend<>对象都可以调用count,且内容一样。
2
格式
//类声明<br>template<typename T><br>class HasFriend{<br>.....<br>public:<br> firend void reports(HasFriend<T>&);//template parameter模板参数<br> ........<br>}<br>
//类定义(与类声明在同一个头文件中)<br>....<br>void reports( HasFriend<double> & hf )<br>{<br> .......<br>}<br><br>void reports(HasFriend<int> & hf){<br>...<br>}
说明
这里的友元函数虽然用到了模板参数,但是本身不是模板<br>类声明中/类定义中,没有template<>打头
在类定义中根据不同情形要具体化。(虽然只有一个函数原型)<br>void reports(HasFriend<T> & hf ) 类定义中,直接这样是不可以的
void reports( HasFriend<double> & hf ) 是HasFriend<double><double>的友元<br>void reports(HasFriend<int> & hf)是HasFriend<int>的友元<br></double></double>
应用代码
<div>// frnd2tmp.cpp -- template class with non-template friends</div><div>#include <iostream></div><div>using std::cout;</div><div>using std::endl;</div><div><br></div><div>template <typename T></div><div>class HasFriend</div><div>{</div><div>private:</div><div> T item;</div><div> static int ct;</div><div>public:</div><div> HasFriend(const T & i) : item(i) {ct++;}</div><div> ~HasFriend() {ct--; }</div><div> friend void counts();</div><div> friend void reports(HasFriend<T> &); // template parameter</div><div>};</div><div><br></div><div>// each specialization has its own static data member</div><div>template <typename T></div><div>int HasFriend<T>::ct = 0;</div><div><br></div><div>// non-template friend to all HasFriend<T> classes</div><div>void counts()</div><div>{</div><div> cout << "int count: " << HasFriend<int>::ct << "; ";</div><div> cout << "double count: " << HasFriend<double>::ct << endl;</div><div>}</div><div><br></div><div>// non-template friend to the HasFriend<int> class</div><div>void reports(HasFriend<int> & hf)</div><div>{</div><div> cout <<"HasFriend<int>: " << hf.item << endl;</div><div>}</div><div><br></div><div>// non-template friend to the HasFriend<double> class</div><div>void reports(HasFriend<double> & hf)</div><div>{</div><div> cout <<"HasFriend<double>: " << hf.item << endl;</div><div>}</div><div><br></div><div>int main()</div><div>{</div><div> cout << "No objects declared: ";</div><div> <font color="#c41230">counts();</font></div><div> HasFriend<int> hfi1(10);</div><div> cout << "After hfi1 declared: ";</div><div> <font color="#c41230">counts();</font></div><div> HasFriend<int> hfi2(20);</div><div> cout << "After hfi2 declared: ";</div><div> counts();</div><div> HasFriend<double> hfdb(10.5);</div><div> cout << "After hfdb declared: ";</div><div> counts(); </div><div> reports(hfi1);</div><div> reports(hfi2);</div><div> reports(hfdb);</div><div> // std::cin.get();</div><div> return 0; </div><div>}</div>
模板类的<br>约束友元
含义
使友元函数本身成为模板,使类的每一个具体化都获得与友元匹配的具体化
步骤
在类定义的前面<br>声明每个模板函数
template<typename T> void counts();<br>template<typename T> void report<font color="#c41230">( T & hf );</font><br>
说明
具体位置见下代码
在函数中再次将<br>模板声明声明友元
template<typename TT><br>class HasFriendT<br>{<br>....<br> friend void counts<TT>( );<br> friend void report<>(HasFriendT<TT> & );
说明
<ul><li>count没有参数,必须使用模板参数语法(<TT>)来指明其具体化。<br></li><li>report的<>为空,因为可以从函数参数推断出模板类型参数。<br></li><li>当然,也可以使用:<br></li></ul>report<HasFriendT<TT>>(Hasfriend<TT> & )
为友元提供模板定义
template<typename T> <br>void counts(){<br>....<br>}<br>
template<typename T><br>void report<font color="#c41230">( T & hf )</font>{<br> ......<br>}
应用代码
<div>// tmp2tmp.cpp -- template friends to a template class</div><div>#include <iostream></div><div>using std::cout;</div><div>using std::endl;</div><div><br></div><div>// template prototypes</div><div>template <typename T> void counts();</div><div>template <typename T> void report(T &);</div><div><br></div><div>// template class</div><div>template <typename TT></div><div>class HasFriendT</div><div>{</div><div>private:</div><div> TT item;</div><div> static int ct;</div><div>public:</div><div> HasFriendT(const TT & i) : item(i) {ct++;}</div><div> ~HasFriendT() { ct--; }</div><div> friend void counts<TT>();</div><div> friend void report<>(HasFriendT<TT> &);</div><div>};</div><div><br></div><div>template <typename T></div><div>int HasFriendT<T>::ct = 0;</div><div><br></div><div>// template friend functions definitions</div><div>template <typename T></div><div>void counts()</div><div>{</div><div> cout << "template size: " << sizeof(HasFriendT<T>) << "; ";</div><div> cout << "template counts(): " << HasFriendT<T>::ct << endl;</div><div>}</div><div><br></div><div>template <typename T></div><div>void report(T & hf)</div><div>{</div><div> cout << hf.item << endl;</div><div>}</div><div><br></div><div>int main()</div><div>{</div><div> counts<int>();</div><div> HasFriendT<int> hfi1(10);</div><div> HasFriendT<int> hfi2(20);</div><div> HasFriendT<double> hfdb(10.5);</div><div> report(hfi1); // generate report(HasFriendT<int> &)</div><div> report(hfi2); // generate report(HasFriendT<int> &)</div><div> report(hfdb); // generate report(HasFriendT<double> &)</div><div> cout << "counts<int>() output:\n";</div><div> counts<int>();</div><div> cout << "counts<double>() output:\n";</div><div> counts<double>();</div><div> // std::cin.get();</div><div> return 0; </div><div>}</div><div><br></div>
说明
每种T类型都有自己的友元函数counts( );
模板类的<br>非约束友元
含义
每个(友元)函数具体化都是每个类具体化的友元。
特点
约束模板友元函数——在类外声明的模板具体化。<br>非约束模板友元函数——在类内部声明模板。<br>
非约束友元模板类型参数与模板类类型参数不同
格式
//类声明<br>template<typename T><br>class ManyFriend<br>{<br>....<br> template<typename C , typename D>friend void show2( C& , D&);<br>}
//类定义<br>template<typename C,typename D><br>void show2( C& c , D& d)<br>{<br> .........<br>}<br>
应用代码
<div>// manyfrnd.cpp -- unbound template friend to a template class</div><div>#include <iostream></div><div>using std::cout;</div><div>using std::endl;</div><div><br></div><div>template <typename T></div><div>class ManyFriend</div><div>{</div><div>private:</div><div> T item;</div><div>public:</div><div> ManyFriend(const T & i) : item(i) {}</div><div> template <typename C, typename D> friend void show2(C &, D &);</div><div>};</div><div><br></div><div>template <typename C, typename D> void show2(C & c, D & d)</div><div>{</div><div> cout << c.item << ", " << d.item << endl;</div><div>}</div><div><br></div><div>int main()</div><div>{</div><div> ManyFriend<int> hfi1(10);</div><div> ManyFriend<int> hfi2(20);</div><div> ManyFriend<double> hfdb(10.5);</div><div> cout << "hfi1, hfi2: ";</div><div> <font color="#c41230">show2(hfi1, hfi2);</font></div><div> cout << "hfdb, hfi2: ";</div><div> show2(hfdb, hfi2);</div><div> // std::cin.get();</div><div> return 0;</div><div>}</div>
模板别名
1.
typedef std::array<double , 12> arrd
arrd gallons; // 相当于std::array<double,12> gallons;
2.(C++11)
template<typename T><br> using arrtype= std::array<T, 12>;
arrtype<double> gollons; //相当于std::array<double,12>;
0 条评论
下一页