继承是面向对象程序设计支持代码重用的重要机制。通过继承,可以在原有类的基础上派生出新类,新类将共享原有类的属性,并且还可以添加新的特性。
好处:代码重用,降低开发成本。
继承分为public,protected,private三种;
继承方式 | 基类公有成员 | 基类保护成员 | 基类私有成员 | 派生类对象 |
公有继承 | public | protected | 不可访问 | 只能访问基类public成员 |
私有继承 | 变成private | 变成private | 不可访问 | 不能访问基类任何成员 |
保护继承 | 变成protected | 变成protected | 不可访问 | 不能访问基类任何成员 |
下例:类B是由类A私有派生而来的,类A中的公有和保护成员被类B继承过来后,作为私有成员,因此,无法直接通过类B的对象访问类A中的任一成员。
在程序的任何部分如果声明有一个类的对象,就可以通过这个对象访问对象所属类中的所有公有成员,但不能访问其私有和保护成员;而一个派生类的成员函数则可以访问所属类中的新声明的所有成员,以及派生它的基类中的公有和保护成员。一个类的私有成员只能被所属类的成员函数访问,在其他任何地方都不可见。
#include<iostream.h>
class A
{
public:
void setx(int a){x=a;}
void sety(int b){y=b;}
intgetx() const{return x;}
intgety() const{return y;}
protected:
int x;
private:
int y;
};
class B:private A
{
public:
void setBx(int a){setx(a);}
void setBy(int b){sety(b);}
intgetBx(){return getx();}
intgetBy(){return gety();}
intgetsum(){return x+gety();}
};
int main()
{
B b;
b.setBx(2);
b.setBy(3);
cout<<″X=″<<b.getBx()<<″\tY=″<<b.getBy()<<endl;
cout<<″X+Y=″<<b.getsum()<<endl;
return 0;
}
派生类构造函数执行的一般顺序如下:
(1) 调用基类的构造函数,调用顺序与声明派生类时基类在声明语句中
出现的顺序一 致。
(2) 调用对象成员的构造函数,调用顺序和第4章所述一样是按照它们在
派生类声明中的顺序。
(3) 调用派生类的构造函数。
析构函数的执行顺序与构造函数正好相反。其顺序是:
(1) 调用派生类析构函数。
(2) 调用派生类中新增对象成员的析构函数,顺序与它们在派生类中声明
的顺序相反。
(3) 调用基类的析构函数,调用顺序与声明派生类时基类在声明语句中出
现的顺序相反。
#include<iostream.h>
class A
{
public:
A(){cout<<″调用类A的构造函数A()″<<endl;}
A(inta,int b)
{
x=a;
y=b;
cout<<″调用类A的构造函数A(int,int)″<<endl;
}
~A(){cout<<″调用类A的析构函数″<<endl;}
protected:
int x;
private:
int y;
};
class B
{
public:
B(){cout<<″调用类B的构造函数B()″<<endl;}
B(int c)
{
z=c;
cout<<″调用类B的构造函数B(int)″<<endl;
}
~B(){cout<<″调用类B的析构函数″<<endl;}
protected:
int z;
};
class C
{
public:
C(){cout<<″调用类C的构造函数″<<endl;}
~C(){cout<<″调用类C的析构函数″<<endl;}
};
class D:public B,privateA,public C
{
public:
D(){cout<<″调用类D的构造函数D()″<<endl;}
D(inta,intb,intc,intd,inte,intf,int g):A(a,b),a(d,e),b(f),B(c),w(g)
{
cout<<″调用类D的构造函数D(int,int,int,int,int,int,int)″<<endl;
}
~D(){cout<<″调用类D的析构函数″<<endl;}
private:
C c;
A a;
B b;
int w;
};
int main()
{
D d1;
D d2(1,2,3,10,20,30,40);
return 0;
}
输出:
调用类B的构造函数B()
调用类A的构造函数A()
调用类C的构造函数
调用类C的构造函数
调用类A的构造函数A()
调用类B的构造函数B()
调用类D的构造函数D()
调用类B的构造函数B(int)
调用类A的构造函数A(int,int)
调用类C的构造函数
调用类C的构造函数
调用类A的构造函数A(int,int)
调用类B的构造函数B(int)
调用类D的构造函数D(int,int,int,int,int,int,int)
调用类D的析构函数
调用类B的析构函数
调用类A的析构函数
调用类C的析构函数
调用类C的析构函数
调用类A的析构函数
调用类B的析构函数
调用类D的析构函数
调用类B的析构函数
调用类A的析构函数
调用类C的析构函数
调用类C的析构函数
调用类A的析构函数
调用类B的析构函数
二义性问题,通过在程序中指定想要访问的成员来消除二义性,这时就需要使用作用域运算符“::”。