15继承和派生
继承和派生
1.继承允许以现有的类为基础来构建新类
2.新类(派生类)继承现有类(基类)的属性和行为
3.派生类可以修改(改变权限或重定义)基类的属性和行为
4.派生类可以增加新的属性和行为
5.派生类对象也是基类对象
6.派生类对象和基类对象可以被统一管理
继承的三种方式
1.公有继承(public)
2.受保护继承(protected)
3.私有继承(private)
在不同方式下,基类中的成员被派生类继承后对外的可见性会有所不同
公有继承(public)
基类中公有成员和受保护成员被继承后可见性不变
受保护继承(protected)
基类中公有成员和受保护成员被继承后都是受保护的
私有继承(private)
基类中公有成员和受保护成员被继承后都是私有的
注意:
基类中的私有成员
1.能被派生类继承
2.不能被派生类的成员函数直接访问
3.可通过基类的公有成员函数或受保护成员函数访问
私有继承例子;
class Mammal
{public:
Mammal();
~Mammal();
......
};
class Lion: private Mammal
{public:
Lion();
~Lion();
......
};
在派生类中重定义基类的成员函数
1.派生类以某种方式继承基类中的所有成员(构造函数、析构函数的使用有特殊规定)
2.如果基类成员函数功能不满足需要——在派生类中可以用同一函数名、相同的参数表重定义该函数(注意:和函数重载不同)
3.关于基类数据成员的重定义(不提倡)
派生类对数据成员和成员函数的使用(一)
在派生类成员函数中,可以直接访问自己定义的数据成员和从基类继承的异名非私有数据成员,但只能以 基类名 ::数据成员名 的方式访问定义于基类的同名非私有数据成员;
可以直接调用自己定义的成员函数和从基类继承的异名非私有成员函数,但只能以基类名 ::函数名 的方式调用定义于基类的同名非私有成员函数(包括重定义和重载两种情况)
在外部函数中,可以通过派生类对象名(对象名.)使用自己定义的接口成员和从基类继承的异名接口成员,但只能以 对象名.基类名 ::接口成员名 的方式使用定义于基类的同名接口成员
示例:
//文件people.h
#if !defined __PEOPLE__H__
#define __PEOPLE__H__
class People
{public:
People(char *str, int s);
~People();
void show();
private:
char *name;
int sex;
};
#endif
//文件people.cpp
#include <string.h>
#include <iostream.h>
#include "people.h"
People::People(char *str, int s)
{ name = new char[strlen(str)+1];
strcpy(name, str);
if (s>0) sex = 1; //男性
else sex = 0; //女性
}
People::~People()
{ delete []name; }
void People::show()
{cout<<"My name is "<<name<<", I am "<<
(sex ? "male." : "female.")<< endl; }
//文件teacher.h
#include "people.h"
#if !defined __TEACHER__H__
#define __TEACHER__H__
class Teacher : public People
{public:
Teacher(char *str, int s,
char *sch, int y);
~Teacher();
void show();
private:
char *school;
int years;
};
#endif
//文件 teacher.cpp
#include <string.h>
#include <iostream.h>
#include "teacher.h"
Teacher::Teacher(char *str, int s,
char *sch, int y)
:People(str, s) //显式调用直接基类的构造函数
{ school = new char[strlen(sch)+1];
strcpy(school,sch);
years = (y>0) ? y : 0; }
Teacher::~Teacher() {delete []school;}
void Teacher::show()
{People::show(); //调用基类被重定义的成员函数
cout<<"I am in "<<school<<" for “
<<years<<" years."<<endl;}
//测试类Teacher
#include <iostream.h>
#include "teacher.h"
main( )
{People Zhang("Zhang lei", 1);
Teacher Xu("Xu Xishan",1,
"National Uni. of Defense Tech.", 23);
Zhang.show();
cout << endl;
Xu.show(); Xu.People::show();
return 0;
}
派生类的构造函数
在派生类中定义了构造函数
定义时显式调用(直接)基类的构造函数
否则,C++在派生类构造函数的函数体前自动插入 :直接基类名( ) (调用直接基类的默认构造函数)
在派生类中未定义构造函数
C++为派生类自动生成如下形式的默认构造函数:派生类名 ( ) :直接基类名( ) { }
派生类和基类的转换
1.派生类和基类具有不同的类型
2.派生类对象也是基类对象,可以作为基类对象处理
3.可以把派生类对象直接赋值给基类对象
4.基类对象不能直接作为派生类对象处理(需要强制类型转换)
类指针
1.类是一种新的用户自定义类型
2.类名可以用来声明变量(类的对象)、数组、指针等
3.类的指针可以操作类的对象,也可以操作派生类的对象(派生类对象也是基类对象)
4.派生类对象和基类对象可以通过基类指针统一操作和管理
类指针操作类对象的几种可能
1.基类指针操作基类对象(自然)
2.派生类指针操作派生类对象(自然)
3.基类指针操作派生类对象(只能访问基类成员)——把派生类对象作为基类对象看(安全)
4.派生类指针操作基类对象——把基类对象作为派生类对象看(危险,禁用)
继承中的构造函数和析构函数
1.基类的构造函数和析构函数是派生类的特殊成员函数,它们既不是派生类的构造函数和析构函数,也不能当作一般成员函数使用
2.派生类的构造函数在构造派生类对象时需要调用基类的构造函数对其中定义于基类的数据成员进行初始化。
需要传递参数时,显式调用
不需要传递参数时,隐式调用
3、基类的析构函数在删除派生类对象时被隐式调用。
C++在派生类析构函数的函数体末尾自动插入:~直接基类名( );
派生类构造函数的执行顺序
1.先调用基类的构造函数初始化从基类继承的数据成员
2.再执行自己的函数体初始化定义于派生类的数据成员
派生类析构函数的执行顺序
1.派生类的析构函数先执行自己的函数体
2.再调用基类的析构函数
多重继承
单继承——一个派生类最多只能有一个直接基类
多重继承——一个派生类可以有多个直接基类
派生类同时继承多个基类的成员,更好的软件重用
可能会有大量的二义性,多个基类中可能包含同名数据成员或成员函数
多重继承的有关问题:二义性
不允许在访问基类成员时产生二义性,如:
class A {public: void f( );};
class B {public: void f( ); void g( );};
class C: public A, public B
{public: void g( ); void h( );};
void C:: h( ) { f( );} //错
C obj;
obj.f( ); //错
obj.A::f( ); //对
例子一:用类指针操作基类和派生类对象
//文件people.h
#if !defined __PEOPLE__H__
#define __PEOPLE__H__
class People
{public:
People(char *str, int s);
~People();
int getSex();
char *getName();
private:
char *name;
int sex;
};
#endif
//文件people.cpp
#include <string.h>
#include <iostream.h>
#include "people.h"
People::People(char *str, int s)
{ name = new char[strlen(str)+1];
strcpy(name, str);
if (s>0) sex = 1; //男性
else sex = 0; //女性
}
People::~People()
{
delete []name;
}
int People::getSex()
{
return sex;
}
char * People::getName()
{static char str[128];
strcpy(str,name);
return str;
}
//文件teacher.h
#include "people.h"
#if !defined __TEACHER__H__
#define __TEACHER__H__
class Teacher : public People
{public:
Teacher(char *str, int s,
char *sch, int y);
~Teacher();
int getWorkYears();
char *getSchool();
private:
char *school; int years;
};
#endif
//文件 teacher.cpp
#include <string.h>
#include "teacher.h"
Teacher::Teacher(char *str,int s,
char *sch,int y)
:People(str, s) //调用基类的构造函数
{ school = new char[strlen(sch)+1];
strcpy(school,sch);
years = (y>0) ? y : 0;
}
Teacher::~Teacher()
{delete []school;}
int Teacher::getWorkYears()
{
return years;
}
char * Teacher::getSchool()
{static char str[1024];
strcpy(str,school);
return str;
}
#include <iostream.h>
#include "teacher.h"
main()
{People p("Zhang San", 1), *pptr;
Teacher t("Li Si", 0,
"Wuhan University", 4), *tptr;
pptr = &p; //用基类指针指向基类对象
cout<<"People p: "<<pptr->getName()<<
","<<(pptr->getSex()?"male":"female")<< endl << endl;
pptr = &t; //用基类指针指向派生类对象
cout<<"Teacher t: "<<pptr->getName()<<
","<<(pptr->getSex()?"male":"female")<<endl;
//要调用定义于派生类中的函数必须进行强制类型转换
cout<<"in"<<((Teacher*)pptr)->getSchool()
<<"for "<<((Teacher*)pptr)->getWorkYears()
<< " years." << endl << endl;
//用派生类指针操作对象
tptr =(Teacher*)&p;//用派生类指针指向基类对象
cout<<"People p: "<<tptr->getName()<<","
<<(tptr->getSex()?"male":"female")<<endl;
//危险,访问了不存在的数据成员,但语法正确
cout<<"in " << tptr->getSchool()<< " for "
<< tptr->getWorkYears()<<" years."<< endl;
tptr = &t; //用派生类指针指向派生类对象
cout<<"People p: "
<< tptr->getName() << ", "
<<(tptr->getSex()?"male":"female")<<endl;
cout<< "in " << tptr->getSchool()<< " for "
<<tptr->getWorkYears()<<" years."<<endl;
return 0;
}
例子二:
#include <iostream.h>
#include <string.h>
#include <assert.h>
char *copy(char *s)
{char *temp=new char[strlen(s)+1];
assert(temp!=0);
strcpy(temp,s);
return temp;
}
class person
{protected:
char *name;
int age;
person(char *n,int a)
{name=copy(n);age=a;}
person( ){ }
~person( )
{delete [] name;}
};
class student:virtual public person
{private:
char *major;
protected:
student(char *m){major=copy(m);}
public:
student(char *n,int a,char *m)
:person(n,a)
{major=copy(m);}
~student( ){delete [] major;}
void print( )
{cout<<name<<endl<<"Age: "
<<age<<" Major: "<<major<<endl;}
};
class faculty:virtual public person
{protected:
char *dept;
faculty(char *d){dept=copy(d);}
public:
faculty(char *n,int a,char *d)
:person(n,a)
{dept=copy(d);}
~faculty( ){delete [] dept;}
void print( )
{cout<<name<<endl<<"Age: "<<age
<<"Department: "<<dept<<endl;
}
};
class professor:public faculty
{private:
int level;
public:
professor(char *n,int a,char *d,int h)
:person(n,a),faculty(d)
{level=h;}
void print( )
{faculty::print( );
cout<<"Level: "<<level<<endl;
}
};
class studentFaculty:public student,
public faculty
{public:
studentFaculty(char *n,int a,char *m,
char *d)
:person(n,a),student(m),faculty(d)
{ }
void print( )
{student::print( );
cout<<"Department: "<<dept<<endl;
}
};
main()
{student myStudent("Zhang",25,"Computer");
faculty myFaculty("Wang",32,"Engineering");
professor myProfessor("Li",50,"Management",2);
studentFaculty myStudentFaculty ("Zhao",23,"English","Foreign Language");
myStudentFaculty.print();
myProfessor.print();
myFaculty.print();
myStudent.print();
return 0;
}
注意:以下的一些错误构造函数
main()
{student myStudent("Computer"); //错
Faculty myFaculty("Engineering"); //错
person myPerson("Li",50); //错
student myStudent1("Zhang",25,"Computer");
person myPerson1(myStudent1); //对
return 0;
}