CPP 14. C++中的代码重用 2020-11-26 浏览量 546 暂无评论 # 第14章 C++中的代码重用 🐸小知识: 1. 获得接口是is-a关系的组成部分,不继承接口是has-a关系的组成部分; 2. 当初始化列表包含多个项目时,这些项目被初始化的顺序为它们被声明的顺序,而不是它们在初始化列表中的顺序; 3. 实现has-a关系的途径:包含、私有继承; 4. 通常,使用包含来建立has-a关系,如果需要访问原有类的保护成员,或需重新定义虚函数,则使用私有继承; ## 14.1 包含对象成员的类 **valarray模板类** ```cpp double gpa[5] = {3.1, 3.5, 3.8, 2.9, 3.3}; valarray v1; valarray v2(8); valarray v3(10, 8); // 8个整型元素,每个都为10 valarray v4(gpa, 4); // 4个双浮点型,gpa前四个 operator[]() size() sum() max() min() ``` ## 14.2 私有继承 使用私有继承,基类的公有成员和保护成员都将成为派生类的私有成员,派生类不继承基类的接口。 使用强制类型转换来访问基类对象 ```cpp class Student : private std::string, private std::valarray { public: ... }; ``` ### 14.2.1 保护继承:保护继承是私有继承的变体 使用保护继承时,基类的公有成员和保护成员都将成为派生类的保护成员,这样就可以在第三代派生类中使用基类的公有方法。 ![](http://lcipm.com/Jineng/picture-bed/uploads/ab2330cd4dc16379476536567505fa82/20201124194025.png) ### 14.2.2 使用using重新定义访问权限 目的:让基类的方法在派生类外面可用 1. 定义一个使用该基类方法的派生类方法; ```cpp double Student::sum() const { return std::valarray::sum(); } ``` 2. 使用一个using声明来指出派生类可以使用特定的基类成员 ```cpp class Student : private std::string, private std::valarray { public: using std::valarray::min; using std::valarray::max; }; ``` ## 14.3 多重继承(MI) 需要处理的问题: 1. 从两个或更多相关基类那里继承同一个类的多个实例; ```cpp SingingWaiter ed; Worker * pw = &ed; 通常,这种赋值将把基类指针设置为派生类对象中的基类对象的地址,但ed中包含两个Worker对象,有两个地址可供选择,所以应使用类型转换来指定对象;(这样将会很复杂) Worker * pw1 = (Waiter *) &ed; Worker * pw2 = (Singer *) &ed; ``` 幸好,C++引入多重继承的同时,引入了一种新技术--虚基类,它使得从多个类(它们的基类相同)派生出的对象只继承一个基类对象。 ```cpp class Singer : virtual public Worker {...}; class Waiter : public virtual Worker {...}; ``` 这样做会出现一个问题:派生类构造函数在向基类传递参数时,由于有2条不同的途径,会产生冲突,所以C++在基类是虚的时,禁止信息通过中间类自动传递给基类。 ```cpp SingingWaiter(const Worker & wk, int p = 0, int v = Singer::other) : Waiter(wk, p), Singer(wk, v) {} 上构造函数将初始化Waiter的成员panache和Singer的成员voice,但wk参数中的信息不会传递给子对象Waiter,这时,编译器将使用Worker的默认构造函数。 SingingWaiter(const Worker & wk, int p = 0, int v = Singer::other) : Worker(wk), Waiter(wk, o), Singer(wk, v) ``` 2. 从两个不同的基类继承同名方法 a. 使用作用域解析运算符 ```cpp SingingWaiter newhire("jhan", 2005, 6, soprano); newhire.Singer::Show(); ``` b. 重新定义 ```cpp void SingingWaiter::Show() { Singer::Show(); } ``` ## 14.4 类模板 生成通用的类声明。模板的具体实现被称为实例化或具体化。 如果在类声明中定义了方法(内联定义),则可以省略模板前缀和类限定符。 ```cpp // stacktp.h -- a stack template #ifndef STACKTP_H_ #define STACKTP_H_ template class Stack { private: enum {MAX = 10}; Type items[MAX]; int top; public: Stack(); bool isempty(); bool isfull(); bool push(const Type & item); bool pop(Type & item); }; template Stack::Stack() { top = 0; } template bool Stack::isempty() { return top == 0; } template bool Stack::isfull() { return top == MAX; } template bool Stack::push(const Type & item) { if (top < MAX) { items[top++] = item; return true; } else return false; } template bool Stack::pop(Type & item) { if (top > 0) { item = items[--top]; return true; } else return false; } // stackem.cpp -- testing the template stack class #include #include #include #include "stacktp.h" using std::cin; using std::cout; int main() { Stack st; char ch; std::string po; ... } ``` 其他类型的模板头: ```cpp 1. template 第二个参数称为非类型或表达式参数,表达式参数可以使整型、枚举、引用或指针。 缺点:每种数组大小都生成自己的模板,即不同的n将生成不同的独立的类声明。 2. template 3. template class Topo { ... }; ``` 模板的具体化 1. 隐式实例化 `ArrayTP stuff;` 2. 显式实例化 `template class ArrayTP;` 3. 显式具体化 用于为特殊类型实例化时,对模板进行修改,使其行为不同。 `template <> class Classname { ... };` **成员模板** ```cpp // tempmemb.cpp -- template members #include using std::cout; using std::endl; template class beta { private: template class hold { private: V val; public: hold(V v = 0) : val(v) {} void show() const {cout << val << endl;} V Value() const {return val;} }; hold q; hold n; public: beta(T t, int i) : q(t), n(i) {} // 模板函数 template U blab(U u, T t) {return (n.Value() + q.Value()) * u / t;} void Show() const {q.show(); n.show();} }; q成员是基于T类型的hold对象,blab()方法的U类型由该方法被调用时的参数值显示确定,T类型是由对象的实例化类型确定。 ``` 模板用作参数 ```cpp template class Thing> class Crab { private: Thing s1; Thing s2; public: Crab() {}; bool push(int a, double x) {return s1.push(a) && s2.push(x);} bool pop(int & a, double & x) {return s1.pop(a) && s2.pop(x);} }; Crab nebula; // Thing将被实例化为Stack ``` 头疼,模板类和友元,每种都适合于什么样的场景呢? 非模板友元函数、约束模板友元函数、非约束模板友元函数 赞赏 微信支付 支付宝支付