day08

来源:互联网 发布:unity3d资源包 编辑:程序博客网 时间:2024/05/16 01:09
二十一 继承(Inheritance)
1 继承的概念
  通过一种机制表达出类型之间的共性和特性的方式,利用已有的数据类型定义新的数据类型,这种机制称为继承。
eg:
   人类 :姓名 年龄 吃饭 睡觉
 学生类 :姓名 年龄 学号 吃饭 睡觉  学习
 教师类 :姓名 年龄 工资 吃饭 睡觉  讲课
 
   人类 :姓名 年龄 吃饭 睡觉
学生类继承人类 :学号 学习
教师类继承人类 :工资 讲课
 
    人类(基类/父类)
   /    \
学生类  教师类(派生类/子类)
 
2 继承语法
class 子类:继承方式  基类{...}
继承方式:
  公有继承:public  
  保护继承:protected
  私有继承:private
 
eg:
class Human{
   string name;
   int age;
};
class Student:public Human{
   //Student类继承Human类
   //在Student中存在一份Human类中的成员
};
 
3 公有继承的特性
1)子类对象会继承基类的属性和行为,通过子类对象访问基类中的成员,如同是基类对象在访问它们一样。
 
子类对象中包含基类的部分称为"基类子对象"
 
2)向上造型(重点掌握)
  将子类类型的指针或引用转换为基类类型指针或引用。
  这种操作性缩小的类型转换,在编译器看来是安全的,可以隐士完成。
eg:
void func(Human& h){...}
void func2(Human* h){...}
int main(void){
   Student s(..);
   func(s);//向上造型
   func2(&s);//向上造型
}
 
3)向下造型
  将基类类型的指针或引用转换为子类类型的指针或引用。
  这种操作性放大的类型转换,在编译器看来是危险的,因为必须显示完成。
 
4)子类继承基类的成员
  在子类中,可以直接访问基类中的公有成员和保护成员,如果是子类自己的成员一样。
  基类的私有成员在子类中存在但是不可见,所以无法直接访问,但是通过基类提供的公有或者保护的借口函数可以间接访问。
 
5)基类的构造函数和析构函数,子类是无法继承的,但是可以在子类自己的构造函数中,通过初始化表显示说明基类子对象的初始化方式。
 
6)子类隐藏基类的成员
   子类和基类中定义同名的成员函数,作用域不同,不会构成重载关系,而是一种隐藏关系。如果需要在子类中访问所隐藏的成员,可以使用"类名::"方式显示指明。
   如果同名的成员函数符合同名不同参两个重载的条件,可以使用using声明的方式将基类的成员函数引入子类的作用域,让其在子类中形成重载关系。
 
4 继承方式和访问控制属性
访问控制    访问控制   内部   子类   外部  友元
限定符        属性         
public        公有成员   ok     ok     ok    ok
protected   保护成员   ok     ok     no    ok
private        私有成员   ok     no     no    ok
===============================================
基类中的  在公有子    在保护子    在私有子
          类中变成    类中变成    类中变成
公有成员  公有成员    保护成员    私有成员
保护成员  保护成员    保护成员    私有成员
私有成员  私有成员    私有成员    私有成员
 
注:私有继承和保护继承不能向上造型
 
5 子类构造函数
1)如果子类的构造函数没有显示指明基类子对象的初始化方式,那么编译器会调用基类的无参构造函数初始化基类子对象。
2)如果希望基类子对象以有参的方式被初始化,必须在子类构造函数的初始化表中显示指明其初始化方式。
3)子类对象的构造过程
--》分配内存
--》构造基类子对象(按继承表的顺序)
--》构造成员子对象(按声明的顺序)
--》执行子类构造函数的代码
 
6 子类的析构函数
1)子类的析构函数,无论是自己定义的还是编译缺省提供的,都会调用基类的析构函数,析构基类子对象。
2)子类对象的析构过程
--》执行子类析构函数的代码
--》析构成员子对象(按声明逆序)
--》析构基类子对象(按继承表逆序)
--》释放内存
 
3)基类的析构函数不会调用子类的析构函数,delete一个指向子类对象的基类指针,实际被调用的仅仅是基类的析构函数,子类中的析构函数不会被调用,有内存泄露的风险。
eg:
class A{..};
class B:public A{};
int main(void){
   A* pa = new B;//pa :指向子类对象的基类指针
   delete pa;//实际只调用基类的析构,内存泄露
}
 
明天:多重继承
 
 

原创粉丝点击