第十三章 类继承

简介: 第十三章 类继承

从已有的已有的类派生出新的类,而派生类继承了原有类的特性包括方法。

1.使用C-风格字符串初始化string对象的时候,调用接受const char * 作为参数的构造函数,使用对象初始化对象的时候,调用接受const string& 作为参数的构造函数。`

String::String(const char *s)
{
  len = std::strlen(s);
  str = new char(len + 1);
  std::strcpy(str, s);
  num_strings++;
}
String::String(const String &st)
{
  num_strings++;
  len = st.len;
  str = new char[len + 1];
  std::strcpy(str, st.str);
}

2.使用公有派生,基类的公有成员将成为派生类的公有成员;基类的私有部分也将成为派生类的一部分,但是只能通过基类的公有和保护的方法访问。


公有派生:

1.继承了基类的数据成员,基类方法

2.需要在派生类里面加自己的数据成员和基类方法。(构造函数必须给新成员和继承的成员提供数据)


3.构造函数:访问权限的考虑

派生不能直接访问基类的私有成员,而必须通过基类的方法进行访问。

在创建派生类对象的时候,在之前必须先创建基类的对象,C++使用成员初始化列表语法来完成这种工作。

必须首先创建基类对象,如果不调用基类构造函数,程序将使用默认的基类构造函数。

有关派生类构造函数的要点如下:

a:首先创建基类对象

b:派生类构造函数应通过成员初始化列表将基类信息传递给基类构造函数

c:派生类构造函数应该初始化派生类新增的数据成员

记住释放顺序与创建对象的顺序相反。首先执行派生类的析构函数,再执行基类的析构函数。创建是先创建基类,再创建派生类。


4.派生类和基类之间的关系

a:派生类可以使用基类的方法,条件是方法不是私有的

b:基类指针可以在不进行显示类型转换的情况下指向派生类,基类引用可以在不进行显示类型转换的情况下引用派生类(不可以将基类对象和地址赋给派生类型引用或指针)

c:基类指针或引用只能用于调用基类的方法。

d:也可以将派生类赋值给基类,但是只会赋值基类里的数据变量。


继承:is-a关系(比如:香蕉是一种水果)

C++有三种继承:公有继承,保护继承,私有继承

公有继承最常用的方式是建立一种is-a关系,即派生类对象也是一个基类对象,可以对基类对象执行的任何操作,也可以对派生类对象执行。

has-a:(比如:午餐有一种香蕉)将香蕉类作为午餐类的数据成员实现。

is-like-a:(比如:律师像一个鲨鱼)但是律师不是鲨鱼所有不能用律师类继承鲨鱼类,没有比喻关系。…


多态公有继承

如果要在派生类中重新定义基类的方法,通常应将基类方法声明为虚的。这样,程序将根据对象类型而不是引用或指针来选择方法版本。为基类声明一个虚析构也是一个惯例。

1.在基类和派生类中的方法前面加了virtual关键字后,当对象被引用或者被指针指向的时候,用引用和指针来调用类方法时,调用的是对象类型的类方法。如果不用virtual则是调用的引用或指针类型的类方法。

2.声明虚构函数是为了确保在释放派生对象的时候。按正确的顺序调用析构函数。

3.virtual关键字只用于类方法原型中,并没有用于类方法的定义里面。


抽象基类

有些相似类进行直接继承的话会出现一些信息冗余和方法不对应的情况,例如圆和椭圆。抽象基类是把多种相似类抽象出它们所有的共性,以便再次生成抽象基类的派生类。

1.要使一个类成为抽象基类,必须要有一个纯虚函数,并且纯虚函数不能再类当中定义(可以在实现文件里面对纯虚函数定义,但是要加上类作用域)。纯虚函数的表达形式如下


virtual double Area()const = 0;

需要再类方法原型后+"= 0".

包含纯虚函数的类只能用作1基类。

2.抽象基类又被称为抽象类,无法创建对象,而具体类是可以创建对象的。


继承和动态内存分配

第一种情况:基类使用new,派生类不使用new

1.不需要为派生类定义显示析构函数,复制析构函数,赋值运算符

是否需要显示析构函数:不需要,因为当执行自身代码后调用基类析构函数,因此默认的析构函数是合适的。

是否需要显示复制构造函数:不需要,因为当调用派生类的默认复制构造函数的时候将使用基类的显示复制构造函数去复制派生类中基类的部分。

是否需要显示赋值函数:不需要,因为当讲一个派生类赋值的时候,将派生类的基类部分使用基类的显示赋值函数进行赋值。


第二种情况:基类使用new,派生类使用new

1.必须为派生类定义显示析构函数,复制构造函数,赋值运算符

析构函数:

析构函数是自动调用基类的析构函数

不做任何操作,自动调用完成

复制构造函数是通过初始化函数列表完成的

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

赋值运算度符是通过在派生类中使用作用域解析运算符来完成的。

hasDMA & hasDMA::operator=(const hasDMA & hs)
{
   if(this == &hs)
      return  * this;
   baseDMA::operator=(hs);
   delete [] style;
   style = new char[std::strlen(hs,style)+1];
   std::strcpy(style,hs.style);
   return *this;
}

总之:对于析构函数是自动调用完成的,对于复制构造函数是初始化成员函数列表完成的,对于赋值运算符是在作用域下解析完成的。


使用动态内存分配和友元的继承

当基类和派生类都有相同的友元函数时,基类的友元函数只能访问基类的数据成员,派生类的友元函数只能访问派生类的数据成员,如果想在派生类中访问基类的数据成员只能调用基类的方法,友元函数一样,但是有一点是基类和派生类都有相同的友元函数则需要将传递给基类友元函数的参数强制转化为基类类型。

std::ostream & operator<<(std::ostream & os,const hasDMA & hs)
{
    os << (oonst baseDMA &)hs;
    os << "Style:"<< hs.style << endl;
    return os;
}
目录
相关文章
|
4月前
|
存储 C++ 容器
第十四章:C++虚函数、继承和多态详解
第十四章:C++虚函数、继承和多态详解
29 0
|
7月前
|
Java
【JavaSE专栏57】妙用this和super关键字,让父类和子类之间来回自如
【JavaSE专栏57】妙用this和super关键字,让父类和子类之间来回自如
|
5月前
|
Java
JavaSE碎碎念:抽象类继承被子类继承之后方法调用关系
JavaSE碎碎念:抽象类继承被子类继承之后方法调用关系
|
8月前
细谈抽象类
抽象类 1.抽象类是被abstract修饰的类 2.抽象类中的抽象方法 3.抽象类中可以有和普通类一样的成员变量和成员方法 4.抽象类不能被实例化 5.那么抽象类不能被实例化要它有何用???
27 0
|
9月前
|
存储 安全 编译器
【巧妙继承】C++玩转继承的神级技巧
【巧妙继承】C++玩转继承的神级技巧
|
10月前
|
C++
自考学习C++ 继承与派生
自考学习C++ 继承与派生
|
10月前
|
Java 数据安全/隐私保护
Java面向对象编程三大特征 - 继承
Java面向对象编程三大特征 - 继承
41 0
|
11月前
《重构2》第十二章-继承
《重构2》第十二章-继承
93 0
|
Java 数据安全/隐私保护
14 java面向对象的三大特征【继承、封装、多态】
封装的实现: 实现三部曲: ①私有化,属性 ②提供公共的getXxx()方法 ②提供公共的setXxx()方法
83 0
|
Java 编译器 测试技术
Java面向对象的三大特征之继承
Java面向对象的三大特征之继承