zoukankan      html  css  js  c++  java
  • C++学习随笔之十一:C++中的代码重用

    引言:C++的一个主要目的是代码重用,提高效率,公有继承是实现这个目的的一种机制。还有其他的机制,本部分主要介绍其他代码重用方法,一种是包含、组合或层次化,另一种是私有或保护继承,通常组合、私有继承和保护继承哟国语实现has-a关系,即新的对类将包含另一个类的对象。还有一种就是和函数模板对应的类模板。

    1.包含对象成员的类:

    包含对象的类就是这样一种类:类中包含了这样的一个类成员:本身是另一个类的对象。这种方法称为包含、组合或层次化。

    C++和约束:C++包含让程序员能够限制程序结构的特性——使用explicit防止单参数构造函数的隐式转换,使用const限制方法修改数据等等。这样做的根本原因是:在编译阶段出现错误要比在运行阶段出现错误要好,要优。

    初始化顺序:当初始化列表包含多个项目时,这些项目被初始化的顺序为它们被声明的顺序,而不是它们在初始化列表中的顺序。例如:

    Student(const char *str,const double *pd,int n):scores(pd,n),name(str){}

    则name成员仍将首先初始化,因为在类定义中它首先被声明。

    接口和实现:使用公有继承是,类可以继承接口,可能还有实现(基类的纯虚函数提供接口,但不提供实现)。获得接口是is-a关系的组成部分。而是用组合,类可以获得实现,但不能获得接口。不继承接口是has-a关系的组成部分。

    2.私有继承和保护继承:

    私有继承:

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

    接口问题:使用公有继承,基类的公有方法将成为派生类的公有方法,。简而言之,派生类将继承基类的接口;这是is-a关系的一部分。使用私有继承,基类的公有方法就成为派生类的私有方法,简而言之,派生类不继承基类的接口。这种不完全继承是has-a的关系的一部分。

    使用私有继承类将继承实现。

    包含是将对象作为一个命名的成员对象添加到类中,而私有继承将对象作为一个未被命名的继承对象添加到类中。一般用术语子对象来表示通过继承或包含添加的对象。

    从上面可知,私有继承的特性和包含(组合)相同,所以,私有继承也可以用来实现has-a关系。

    访问基类的方法:使用包含时将使用对象名来调用方法,而是用私有继承时将使用类名和作用域解析操作符::来调用方法

    访问基类对象:一般使用强制类型转换。例如:Student类是string类派生而来的:

    cosnt string & Student::Name()const

    {

    return (const string &) *this;

    }

    访问基类的友元函数:用类名显示地限定函数名不适合与友元函数,因为友元不是类成员,不过,可以通过显式地转换为基类来调用正确的函数。例如,对于下面的友元函数定义:

    ostream & operator<<(ostream & os,Student & stu)

    {

    os <<"Scores for " <<(const string &) stu <<":\n";

    ...

    }

    如果pstu是一个Student对象,则下面的语句:

    cout<<pstu;将调用上述函数,stu将是指向pstu的引用,而os将是指向cout的引用。下面的代码:

    os<<"Scores for " << (const string &) stu <<":\n"; 显式地将stu转换为string对象的引用,这与operator<<(ostream &,cosnt String &)函数匹配

    引用stu不会自动转换为sting引用。根本原因在于,在私有继承中,在不进行显式类型转换的情况下,不能将指向派生类的引用或指针赋给基类应用或指针。

    不过,即使这个例子使用的是公有继承,也必须使用显示类型转换。原因之一是,如果不使用类型转换,下面代码将与友元函数原型匹配,从而导致递归调用:os<<stu; 另一个原因是,如果使用的多重继承,编译器无法确定应转换为哪个基类,如果两个基类都提供了函数operator<<()。

    3.多重继承:

    多重继承,顾名思义,就是使用多个基类的继承(multiple inheritance,MI),描述的是有多个直接基类的类。

    4.类模板:

    定义:开头用 template <class Type>  或者 template <typename Type>,模板的具体实现就是实例化或具体化。

    例如创建一个堆栈类模板示例:

    #pragma once//

    #include <iostream>

    using namespace std;

    template <class Type>

    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 <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(Type & item)

    {

    if(top > 0)

    {

    item = items[--top];

    return true;

    }

    else

    return false;

    }

    指针类型类模板:既然可以将内置类型或类对象用作类模板的类型,那么指针可以吗?答案是肯定的。但是,要注意正确使用指针。

    使用指针堆栈的方法之一是,让调用程序提供一个指针数组,其中每隔指针都指向不同的字符串。把这些指针都放在指针堆栈是有意义的,因为每个指针都将指向不同的字符串。注意,创建不同指针是调用程序的职责,而不是堆栈的职责。堆栈的认为是管理指针,而不是创建指针。

    模板还可以带参数,例如:template <class Type,int n>,里面的 int n称为非类型或表达式参数,但是表达式参数有一定的限制。只可以是整型、枚举、引用或指针。还可以使用多个类型参数,例如 template <class T1,class T2>

    默认类型模板参数:类模板的一项特性是,可以为类型参数提供默认值:

    temp <class T1,class T2 = int> 

    class Topo

    {

    ...

    };

    这样,如果省略了T2的值,编译器将使用int:

    Topo<double,double> m1;    //T1 is double,T2 is double

    Topo<double> m2; //T1 is double ,T2 is int

    标准模板库将此使用该特性,将默认类型设置为类

    虽然可以为类模板类型参数提供默认值,但不能为函数模板参数提供默认值。不过,可以为非类型参数提供默认值,这对于函数模板和类模板都都是适用的。

    模板的其他特性:可用作结构、类或模板类的成员;可将模板用作参数

    模板类和友元:模板声明也可以有友元。模板的友元分为3类:

    ● 非模板友元

    ● 约束(bound)模板友元,即友元的类型取决于类被实例化时的类型

    ● 非约束(unbound)模板友元,即友元的所有具体化都是类的每一个具体化的友元

  • 相关阅读:
    Android开发之下载服务器上的一张图片到本地java代码实现HttpURLConnection
    控制台——屏蔽Ctrl+C快捷键对窗体的关闭功能
    控制台——禁用关闭按钮
    控制台——对WIN32 API的使用(user32.dll)
    控制台——对窗口句柄的操作
    控制台——防止程序重复启动
    Json——一般应用
    SQL——将两列合并成一列
    Xamarin在VS2012没有智能提示的解决办法
    C#的Xamarin开发小米盒子应用并以WCF实现微信通知
  • 原文地址:https://www.cnblogs.com/JczmDeveloper/p/2964826.html
Copyright © 2011-2022 走看看