C++ primer plus 阅读记录-类继承

从一个类派生出另一个类时,原始类称为基类,继承类称为派生类。
派生类不能直接访问基类的私有成员,而必须通过基类方法进行访问。

有关派生类构造函数的要点如下:
首先创建基类对象;
派生类构造函数应通过成员初始化列表将基类信息传递给基类构造函数;
派生类构造函数应初始化派生类新增的数据成员;
释放对象的顺序与创建对象的顺序相反,即首先执行派生类的析构函数,然后自动调用基类的析构函数。

基类指针可以在不进行显式类型转换的情况下指向派生类对象;基类引用可以在不进行显式类型转换的情况下引用派生类对象。
然而,基类指针或引用只能用于调用基类方法。

注意:如果要在派生类中重新定义基类的方法,通常应将基类方法声明为虚的(virtual)。这样,程序将根据对象类型而不是引用或指针的类型来选择方法版本。为基类声明一个虚析构函数也是一种惯例。
关键字virtual只用于类声明的方法原型中,而没有用于方法定义中。

隐式向上强制转换使基类指针或引用可以指向基类对象或派生类对象,因此需要动态联编。C++使用虚成员函数来满足这种需求。

如果要在派生类中重新定义基类的方法,则将它设置为虚方法;否则,设置为非虚方法。
这里写图片描述

友元不能是虚函数,因为友元不是类成员,而只有成员才能是虚函数。如果由于这个原因引起了设计问题,可以通过让友元函数使用虚成员函数来解决。

访问控制: protected
private 和 protected之间的区别只有在基类派生类中才会表现出来。派生类的成员可以直接访问基类的保护成员,但不能直接访问基类的私有成员。因此,对于外部世界来说,保护成员的行为与私有成员相似;但对于派生类来说,保护成员的行为与公有成员相似。

抽象基类(abstract base class, ABC)
C++通过使用纯虚函数pure virtual function提供未实现的函数。纯虚函数声明的结尾处为 =0,如
public:
virtual double Area() const =0; //pure virtual function

当类声明中包含纯虚函数时,则不能创建该类的对象。这里的理念是,包含纯虚函数的类只用作基类。要成为真正的ABC, 必须至少包含一个纯虚函数。

总之,ABC描述的是至少使用一个纯虚函数的接口,从ABC派生出的类将根据派生类的具体特征,使用常规虚函数来实现这种接口。这种“接口约定”,确保了从ABC派生的所有组件都至少支持ABC指定的功能。

如果希望派生类的友元函数能够使用基类的友元函数,可以通过强制类型转换将派生类引用或指针转换为基类引用或指针,然后使用转换后的指针或引用来调用基类的友元函数。

ostream & operator<<(ostream & os, const hasDMA & hs)
{
    os << (const baseDMA &)hs;
    os << "Style: " << hs.style << endl;
    return os;
}

类函数小结
这里写图片描述

继承和动态内存分配示例

#ifndef DMA_H_
#define DMA_H_
#include <iostream>

class baseDMA
{
private:
    char* label;
    int rating;

public:
    baseDMA(const char* l= "null", int r = 0);
    baseDMA(const baseDMA & rs);
    virtual ~baseDMA();
    baseDMA & operator=(const baseDMA & rs);
    friend std::ostream & operator<<(std::ostream & os, const baseDMA & rs);
};


// derived class without DMA
// no destructor needed
// uses implicit copy constructor
// uses implicit assignment operator
class lacksDMA :public baseDMA
{
private:
    enum {COL_LEN = 40};
    char color[COL_LEN];
public:
    lacksDMA(const char* c="blank", const char* l= "null", int r = 0);
    lacksDMA(const char* c, const baseDMA& rs);
    friend std::ostream & operator<<(std::ostream &os, const lacksDMA & rs);
};

// derived class with DMA
class hasDMA :public baseDMA
{
private:
    char *style;
public:
    hasDMA(const char* c="null", const char* l= "null", int r = 0);
    hasDMA(const char* c, const baseDMA& rs);
    hasDMA(const hasDMA & rs);
    ~hasDMA();

    hasDMA & operator=(const hasDMA & rs);
    friend std::ostream & operator<<(std::ostream &os, const hasDMA & rs);

};

#endif
#include "dma.h"
#include <cstring>

baseDMA::baseDMA(const char* l, int r)
{
    label = new char[std::strlen(l)+1];
    std::strcpy(label,l);
    rating = r;
}

baseDMA::baseDMA(const baseDMA & rs)
{
    label = new char[std::strlen(rs.label)+1];
    std::strcpy(label, rs.label);
    rating = rs.rating;
}

baseDMA::~baseDMA()
{
    delete [] label;
}

baseDMA & baseDMA::operator=(const baseDMA & rs)
{
    if(this == &rs)
        return *this;

    delete [] label;
    label = new char[std::strlen(rs.label)+1];
    std::strcpy(label, rs.label);
    rating = rs.rating;
    return *this;
}


std::ostream & operator<<(std::ostream & os, const baseDMA & rs)
{
    os << "Label: " << rs.label << std::endl;
    os << "Rating: " << rs.rating << std::endl;
    return os;
}

lacksDMA::lacksDMA(const char* c, const char* l, int r) : baseDMA(l,r)
{
    std::strncpy(color, c, COL_LEN-1);
    color[COL_LEN-1] = '\0';
}

lacksDMA::lacksDMA(const char* c, const baseDMA& rs) : baseDMA(rs)
{
    std::strncpy(color, c, COL_LEN-1);
    color[COL_LEN-1] = '\0';
}

std::ostream & operator<<(std::ostream &os, const lacksDMA & rs)
{
    os << (const baseDMA &) rs;  //强制类型转换
    os << "Color: " << rs.color <<std::endl;
    return os;
}

hasDMA::hasDMA(const char* c, const char* l, int r) : baseDMA(l,r)
{
    style = new char[std::strlen(c)+1];
    std::strcpy(style, c);
}

hasDMA::hasDMA(const char* c, const baseDMA& rs): baseDMA(rs)
{
    style = new char[std::strlen(c)+1];
    std::strcpy(style, c);
}

hasDMA::hasDMA(const hasDMA & rs): baseDMA(rs)
{
    style = new char[std::strlen(rs.style)+1];
    std::strcpy(style, rs.style);
}

hasDMA::~hasDMA()
{
    delete [] style;
}

hasDMA & hasDMA::operator=(const hasDMA & rs)
{
    if(this == &rs)
        return *this;

    baseDMA::operator=(rs); // copy base portion
    delete [] style;
    style = new char[std::strlen(rs.style)+1];
    std::strcpy(style, rs.style);
    return *this;
}

std::ostream & operator<<(std::ostream &os, const hasDMA & rs)
{
    os << (const baseDMA &) rs;  //强制类型转换
    os << "Style: " << rs.style <<std::endl;
    return os;
}
#include "dma.h"
#include <iostream>

int main()
{
    using std::cout;
    using std::endl;

    baseDMA shirt("Portabelly", 8);
    lacksDMA balloon("red", "Blimpo", 4);
    hasDMA map("Mercator", "Buffalo keys", 5);
    cout << "Displaying baseDMA object:\n";
    cout << shirt <<endl;
    cout << "Displaying lacksDMA object:\n";
    cout << balloon <<endl;
    cout << "Displaying hasDMA object:\n";
    cout << map <<endl;

    lacksDMA balloon2(balloon);
    cout << "Displaying lacksDMA object:\n";
    cout << balloon2 <<endl;
    hasDMA map2;
    map2 = map;
    cout << "Result of hasDMA assignment:\n";
    cout << map2 << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值