继承与派生初步
一、什么是继承与派生?
新类从已有类那里得到已有的成员(数据成员和成员函数)。新类称为派生类或子类,已有类称为基类或父类。也可以说,已有类产生新类的过程就是类的派生。
注意:
1、 类的继承和派生是面向对象的最重要特征之一;
2、 类的继承与派生大大提高了C++的代码重用率;
3、 派生类可以作为基类继续派生出多个新类;
4、 一个基类可以派生多个派生类,一个派生类也可以从多个基类继承而来(多继承)。
5、 构造函数和析构函数不能被继承(派生);
6、 类的继承方式有三种:public,private,protected;
二、类的三种继承方式(基类的成员在派生类中的等价权限)
public继承:
基类(父类) |
派生类(子类) |
public |
public |
protected |
protected |
private |
× |
特点:派生类拥有了基类的共有成员和保护成员,是最常用的继承方式。
private继承:
基类(父类) |
派生类(子类) |
public |
private |
protected |
private |
private |
× |
特点:把基类中的成员私有化。
protected继承:
基类(父类) |
派生类(子类) |
public |
protected |
protected |
protected |
private |
× |
注意:在继承关系中,基类的private成员不但不能被类外访问(对应用程序隐藏),而且对派生类也是隐藏,而基类的protected成员不能被类外访问,但对派生类来说是不隐藏的。
三、派生类的构造函数和析构函数
基类中两类特殊函数不能被继承——构造函数和析构函数。
生成对象时,先调用基类的默认构造函数,再调用派生类的默认构造函数;撤销对象时,先调用派生类的默认析构函数,再调用基类的默认析构函数。
class Person
{
private:
char name[10];
public:
Person(){};
};
class Student:public Person
{
private:
int grade;
public:
Student(){};
};
void main()
{
Student s;//生成对象时,先调用Person的默认构造函数,再调用Student的默认构造函数
}//撤销对象时,先调用Student的默认析构函数,再调用Person的默认析构函数
当我们想在初始化s的时候,获得一个姓名和年级,该怎么办呢?年级我们完全可以通过重载Student来初始化,至于姓名,我们可以重载一个Person的构造函数。通过向基类构造函数传递参数实现基类的初始化。如下:
Person(char *n)
{strcpy(name,n);}
Student(int g, char *n):Person(n)//向基类构造函数传递参数
{grade = g;}
完整的调试程序如下:
#include
#include
class Person
{
private:
char name[10];
public:
Person(char *n){strcpy(name,n);}
Person(){};
void displayName(){cout<
};
class Student:public Person
{
private:
int grade;
public:
Student(){};
Student(int g, char *n):Person(n)
{grade = g;}
void displayGrade(){cout<
};
void main()
{
Student s(2,"张飞");
s.displayName();
s.displayGrade();
}
派生类含有对象成员的情况,可以把对象成员看成一个普通的变量类型。如下程序:
#include
#include
class Cource
{
private:
char name[20];
int mark;
public:
Cource(char *n, int m)
{strcpy(name,n);mark = m;}
void displayMark(){cout<
};
class Person
{
private:
char name[10];
public:
Person(char *n){strcpy(name,n);}
Person(){}
void SetName(char *n){strcpy(name,n);}
void displayName(){cout<
};
class Student:public Person
{
private:
int grade;
Cource c;
public:
void displayGrade(){cout<
Student(int g,char *n1,char *n2,int m):Person(n1),c(n2,m)
{grade = g;}
void SetGrade(int g){grade = g;}
};
void main()
{
Student s(2,"张飞","面向对象程序设计",98);
s.displayName();
s.displayGrade();
}
为了更好的理解我们可以把:
Student(int g,char *n1,char *n2,int m):Person(n1),c(n2,m)
{grade = g;}
等价写成: Student(int g,char *n1,char *n2,int m):Person(n1),c(n2,m),grade(3){}
一般会重载没有参数的构造函数,便于建立没有初值的对象,更完整的程序见附录!
四、多继承
多继承和单继承的区别在于它们基类的个数。
例:
class Teacher
{};
class Student
{};
class Teach_Assistant:public Teacher,public Student
{
…
}
如果Teacher 和Student基类相同,可能会产生二义性问题!如:
#include
#include
class Person
{
private:
char name[10];
public:
Person(char *n){strcpy(name,n);}
Person(){}
void displayName(){cout<<"输出名字!";}
};
class Student:public Person
{};
class Teacher:public Person
{};
class Teach_Assistant:public Teacher,public Student
{
//public:
// void displayName();
};
//void Teach_Assistant::displayName()
//{
// Teacher::displayName();
//}
void main()
{
Teach_Assistant ta;
ta.displayName();
}
当如上注释掉几条语句后,编译无法通过!
五、虚基类
解决二义性问题!如下:
#include
#include
class Person
{
private:
char name[10];
public:
Person(char *n){strcpy(name,n);}
Person(){}
void displayName(){cout<<"输出名字!";}
};
class Student:virtual public Person
{};
class Teacher:virtual public Person
{};
class Teach_Assistant:public Teacher,public Student
{};
void main()
{
Teach_Assistant ta;
ta.displayName();
}
-----------------------------------------------------------------------
附录:
#include
#include
class Cource
{
private:
char name[20];
int mark;
public:
Cource(){}
Cource(char *n, int m)
{strcpy(name,n);mark = m;}
void displayMark(){cout<
void Set(char *n,int m){strcpy(name,n);mark = m;};
};
class Person
{
private:
char name[10];
public:
Person(char *n){strcpy(name,n);}
Person(){}
void SetName(char *n){strcpy(name,n);}
void displayName(){cout<
};
class Student:public Person
{
private:
int grade;
Cource c;
public:
void displayGrade(){cout<
Student(){}
Student(int g,char *n1,char *n2,int m):Person(n1),c(n2,m)
{grade = g;}
void SetStu(int g,char *n1,char *n2,int m)
{
grade = g;
SetName(n1);
c.Set(n2,m);
}
void SetGrade(int g){grade = g;}
};
void main()
{
Student s(2,"张飞"," 面向对象程序设计 ",98);
s.displayName();
s.displayGrade();
cout<
Student ss;
ss.SetStu(2,"刘备"," 面向对象程序设计 ",93);
ss.displayName();
ss.displayGrade();
cout<
}