是面向对象程序设计是代码可以复用的最重要的手段,它允许程序员在保持原有的类的特性的基础下进行拓展,增加功能。 这样产生的类被称为派生类;
class Person
{
public:
void Print()
{
cout << "name:" << _name << endl; cout << "age:" << _age << endl;
}
protected:
string _name = "peter"; // 姓 名
int _age = 18; // 年 龄
};
// 继承后父类的Person的成员(成员函数+成员变量)都会变成子类的一部分。这里体现出了Student和Teacher复用了Person的成员。下面我们使用监视窗口查看Student和Teacher对象,可以看到变量的复用。调 用Print可以看到成员函数的复用。
class Student : public Person
{
protected:
int _stuid; // 学 号
};
class Teacher : public Person
{
protected:
int _jobid; // 工 号
};
int main()
{
Student s; Teacher t; s.Print();
t.Print();
return 0;}
注意:
1.在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中 扩展维护性不强。
#include
using namespace std;
class A
{
public:
void print2(){cout << "A print2!" << endl;}
};
class B : public A
{
public:
void print2(int x)
{
cout << "B print2 !" << x << endl;
}
};
int main()
{
B b;
b.print2();
return 0;
}
编译失败!
由结果可知,已经不能从B的对象中直接用函数名访问print2()了。
单继承+多继承
单继承:
多继承:
菱形继承:
菱形继承的问题:从上面的对象成员模型构造,可以看出菱形继承有数据冗余和二义性的问题。在D的对象中B成员会有两份。
//公共基类
class N
{
public:
N(int data1, int data2, int data3) :
m_data1(data1),
m_data2(data2),
m_data3(data3)
{
std::cout << "call common constructor" << std::endl;
}
virtual ~N(){}
void display()
{
std::cout << m_data1 << std::endl;
}
public :
int m_data1;
int m_data2;
int m_data3;
};
class A : /*virtual*/ public N
{
public:
A() :N(11, 12, 13), m_a(1)
{
std::cout << "call class A constructor" << std::endl;
}
~A(){}
public :
int m_a;
};
class B : /*virtual*/ public N
{
public:
B() :N(21, 22, 23),m_b(2)
{
std::cout << "call class B constructor" << std::endl;
}
~B(){}
public :
int m_b;
};
class C : public A , public B
{
public:
//负责对基类的初始化
C() : A(), B(),
m_c(3)
{
std::cout << "call class C constructor" << std::endl;
}
void show()
{
std::cout << "m_c=" << m_c << std::endl;
}
public :
int m_c;
};
虚拟继承可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系,在Student和Teacher的继承Person时使用虚拟继承,即可解决问题。需要注意的是,虚拟继承不要在其他地方去使用。
虚拟继承和普通继承的区别:
如何解决: