基础知识:
|定义:在已有类的基础上创建新类的过程;
B类继承A类内容,称A类为基类(父类),B类为派生类(子类);
称类A派生类B;
|语法形式:
class 派生类(子类):基类名表
{
数据成员和成员函数声明;
};|基类名表 构成
访问控制 基类名1,访问控制 基类名2,访问控制 基类名n;
|访问控制 表示派生类对基类的继承方式,使用的关键字:
public 公有继承
private 私有继承
protected 保护继承
无论何种继承方式,派生类都不能直接使用基类的私有成员;
|派生类的生成过程:
1、吸收基类成员(除构造、析构外,全部吸收,不一定可见);
2、改造基类成员(通过在派生类中定义同名成员函数和数据成员,可屏蔽(隐藏)在派生类中不起作用的部分基类成员);
3、添加派生类的新成员(需要在派生类中添加新成员,以保证派生类自身特殊属性和行为的实现);
|基础样例:
#include <iostream>
using namespace std;
class A
{
public:
int a;
int b;
private:
int c;
protected:
int d;
};
class B: protected A
{
int c; };
int
main( )
{
cout << "size of A is"<< sizeof(A);
cout << "size of B is" << sizeof(B);
}
公有继承:
基类 | 派生类 |
私有成员 |
|
公有成员 | 公有成员 |
保护成员 | 保护成员 |
| 私有成员 |
| 保护成员 |
| 公有成员 |
样例:
定义基类person(无构造函数)
数据成员:姓名、性别、年龄(私有成员)
定义公有成员函数set()/dispaly()
再定义学生类为派生类(采用公有继承)
增加学号、班级、专业、入学成绩
定义公有成员函数set()/display()
代码样例:
#include<iostream>
#include <string>
using namespace std;
class Person
{
string name;
int age;
string sex;
public:
void set_p() {
cout<<"name\tage\tsex"<<endl;
cin>>name>>age>>sex;
}
void show_p() {
cout<<name<<" "<<age<<" "<<sex<<endl;
}
};
class student :public Person
{
string no;
string zhuanye;
string t_class;
float score;
public:
void set_t(){
set_p(); //调用继承于基类的成员函数访问继承于基类的私有数据成员,当基类和派生类函数名相同时可用Person::基类函数名,调用基类函数
cout<<"zhuanye\tt_class\tscore"<<endl;
cin>>zhuanye>>t_class>>score;
}
void show_t() {
show_p();//当基类和派生类函数名相同时可用Person::基类函数名,调用基类函数
cout<<zhuanye<<" "<<t_class<<" "<<score<<endl;
}
};|重名函数:
当在派生类中定义了与基类同名的成员,在派生类中访问时,派生类中的函数起作用;
可用基类名::成员的形式调用被屏蔽的同名函数;
例:
class base
{ public :
int a , b ;
} ;
class derived : public base
{ public :
int b , c ;
} ;
void f ()
{ derived d ;
d . a = 1 ;
d . base :: b = 2 ;
d . b = 3 ;
d . c = 4 ;
};base | a | b |
|
|
derived | a | b | b | c |
|派生类中访问静态成员:
基类中若定义静态成员,将被所有派生类共享(包括基类);
派生类中访问静态成员的形式:
类名::成员;
对象名.成员;
样例:
#include<iostream>
using namespace std ;
class B
{ public:
static void Add() { i++ ; }
static int i;
void out() { cout<<"static i="<<i<<endl; }
};
int B::i=0;
class D : private B
{ public:
void f()
{ i=5;
Add();
B::i++;
B::Add();
}
};
int main()
{ B x; D y;
x.Add();
x.out();
y.f();
cout<<"static i="<<B::i<<endl;
cout<<"static i="<<x.i<<endl;
//cout<<"static i="<<y.i<<endl;
}运行结果:
static i=1
static i=8
static i=8
|基类的初始化:
在构建派生类对象时,用指定参数调用基类的构造函数来初始化派生类继承基类的数据;
派生类构造函数的声明形式为:
派生类构造函数(变元表):基类(变元表),对象成员1(变元表)...
构造函数的执行顺序为:基类、对象成员、派生类;
样例:
#include<iostream>
using namespace std ;
class parent_class
{ int data1 , data2 ;
public :
parent_class ( int p1 , int p2 ) { data1 = p1; data2 = p2; }
int inc1 () { return ++ data1; }
int inc2 () { return ++ data2 ; }
void display () {cout << "data1=" << data1 << " , data2=" << data2 << endl ; }
};
class derived_class : private parent_class
{ int data3 ;
parent_class data4 ;
public:
derived_class ( int p1 , int p2 , int p3 , int p4 , int p5 ): parent_class ( p1 , p2 ) , data4 ( p3 , p4 )
{ data3 = p5 ; }
int inc1 ( ) { return parent_class :: inc1 ( ) ; }
int inc3 ( ) { return ++ data3 ; }
void display ( )
{ parent_class :: display ( ) ; data4.display ( ) ;
cout << "data3=" << data3 << endl ;
}
} ;
int main ( )
{ derived_class d1 ( 17 , 18 , 1 , 2 , -5 ) ;
d1 . inc1 ( ) ;
d1 . display ( ) ; }派生类构造函数析构函数的使用原则:
1、基类的构造函数和析构函数不能够被继承;
2、若基类中无构造函数或有无参函数,派生类中也不可以定义构造函数;
3、如果基类没有无参函数的构造函数,派生类必须定义构造函数;
4、若派生类的基类也是派生类,则每个派生类只负责直接相关的基类的构造;
5、派生类是否定义析构函数与所属的基类无关;
|派生类的数据成员既包括基类的数据成员,也包括派生类新增成员;
如何在派生类中对基类成员进行初始化?
可调用基类构造函数对基类成员进行初始化;
派生类构造函数的一般形式:
派生类::派生类名(参数总表):基类名(参数表)
{
派生类新增成员的初始化语句;
}
1、当派生类无对象成员时:
创建派生类对象时,构造函数的执行顺序为:基类的构造函数、派生类的构造函数;
撤销派生类对象时,执行顺序:派生类的析构函数、基类的析构函数;
2、当派生类中含有对象成员时:
创建派生类对象时,执行顺序:基类的构造函数、对象成员的构造函数、派生类的构造函数;
撤销派生类对象时,执行顺序:派生类的构造函数、对象成员的构造函数、基类的构造函数;
样例:
#include<iostream.h>
class base
{
public:
base(){cout<<"constructing base class"<<endl;}
~base(){cout<<"destructing base class"<<endl; }
};
class subs:public base
{
public:
subs(){cout<<"constructing sub class"<<endl;}
~subs(){cout<<"destructing sub class"<<endl;}
};
void main()
{
subs s;
} 运行结果:constructing base class
constructing sub class
destructing sub class
destructing base class
|多继承:
定义:一个类由多个直接基类的继承关系称为多继承;
多继承声明形式:
class 派生类名 : 访问控制 基类名1 , 访问控制 基类名2 , … , 访问控制 基类名n
{
数据成员和成员函数声明
};
|多继承派生类的构造和访问:
多个基类的派生类构造函数可以用初始式调用基类构造函数初始化数据成员。
执行顺序与单继承构造函数情况类似;
多个直接基类构造函数执行顺序取决于定义派生类时指定的各个继承基类的顺序;
一个派生类对象拥有多个直接或间接基类的成员。不同名成员访问不会出现二义性;
如果不同的基类有同名成员,派生类对象访问时应该加以识别;
多继承的构造函数:
派生类名(参数总表):基类名1(参数表1),基类名2(参数表2),…,基类名n(参数表n)
{
// 派生类新增成员的初始化语句
} 多继承方式下构造函数的执行顺序:
先执行所有基类的构造函数
再执行对象成员的构造函数
最后执行派生类的构造函数
处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的基类顺序,与派生类构造函数中所定义的成员初始化列表顺序没有关系,
内嵌对象成员的构造函数执行顺序与对象在派生类中声明的顺序一致。
析构函数名同样与类名相同,无返回值、无参数,而且其定义方式与基类中的析构函数的定义方式完全相同;
功能是在派生类中对新增的有关成员进行必要的清理工作;
析构函数的执行顺序与多继承方式下构造函数的执行顺序完全相反,首先对派生类新增的数据成员进行清理,再对派生类对象成员进行清理,最后才对基类继承来的成员进行清理;
|赋值兼容规则:
指在程序中需要使用基类对象的任何地方,都可以用公有派生类的对象来替代;
所指的替代包括以下情况:
派生类的对象可以赋给基类对象;
派生类的对象可以初始化基类的引用;
派生类的对象的地址可以赋给基类类型的指针;
|赋值兼容的可行性:
1、通过公有继承:
派生类得到了除了构造、析构函数以外的所有成员;
且这些成员的访问控制属性也和基类完全相同;
这样,它便具备了基类的所有功能;
2、利用赋值兼容的规则:
派生类的对象可以赋给基类对象(强制类型转换);(Base b;Derived d;b=d;)
派生类的对象可以初始化基类的引用;(Derived d;Base &br=d;)
派生类的对象的地址可以赋给基类类型的指针;(Derived d;Base*bptr=&d;)
可以把指向派生类对象的指针赋值给基类对象的指针;(Derived *dptr,obj;dptr=&obj;Base *bptr=dptr;)
|在替代后,派生类对象就可以作为基类的对象使用,但只能使用从基类继承的成员;
二、心得体会:
继承的应用,可以让我们更好的理顺我们的逻辑思路,减少冗余的代码,简化代码的篇幅;
继承中,基类与派生类的关系如同父子一般,顾名思义,即为儿子从父亲那里继承其内容,后有扩充自己的内容;
继承并不是单纯的一对一继承,可以一对多,也可以多对一的多继承,一对多即为想使俩个类所拥有的内容有相同的部分,可继承同一个类,多对一则为一个类继承包含多个类的内容;
要想应用好继承,首先要缕清自己的思路,想好其中的逻辑关系,而且要课下多实践,才能真正的发现盲区,以及可以熟练知识;
7362

被折叠的 条评论
为什么被折叠?



