1.面向对象的程序设计的三大要素是封装、继承、多态。封装是用访问限定符将成员变量和成员函数包装,以实现不同权限的访问目的,访问限定符有public、protected、private。一般的将成员函数设为private,成员函数设为public或protected。
继承是面向对象复用的重要手段,子类继承父类,是两个类型之间的关系建模,共享公有的东西,实现各自本质不同的东西。在继承关系里,派生类继承基类的成员,以此达到复用的目的。
多态就是多种形态,同样的一份代码,由于调用对象的不同,实现不同的结果。如同样是买票的函数,成人调用和儿童调用其结果不同。
2.继承关系:public(公有继承)、 protected(保护继承)、 private(私有继承)
三种继承关系下基类成员在派生类中的访问关系
小结:不论哪种继承方式,在派生类内部都可访问基类的公有成员和保护成员,只不过继承下来变为派生类的保护或私有成员而已。基类的私有成员存在但在子类中不可访问。保护限定符是因继承才出现的,如果基类成员不想被基类对象直接访问,但在派生类中能访问,那就定义为保护成员。大多数情况下,使用的都是public继承。
3.继承的赋值兼容规则
class Person
{
private:
string _name;
};
class Student:public Person
{
private:
int _num;
};
int main()
{
Person p;
Student s;
//p = s;//子类对象可以赋值给父类对象(切片)
s = p;//父类对象不能赋值给子类对象
Person* p1 = &s;//父类的指针/引用可以指向子类对象
Person& p2 = s;
return 0;
}
4.单继承与多继承
在派生类中最好不要定义和基类中相同的函数,会构成隐藏(重定义),屏蔽基类中的同名函数。此概念不同于重写(在多态中)。在继承关系里面,编译器会默认合成六个默认成员函数,也就是说,以合成构造函数为例,派生类只初始化自己的成员,基类部分调用基类的构造。
5.菱形继承与菱形虚拟继承
class A
{
protected:
int _a;
};
class B : public A
{
protected:
int _b;
};
class C : public A
{
protected:
int _c;
};
class D : public B,public C
{
protected:
int _d;
};
int main()
{
D d;
d._a = 1;//菱形继承的二义性,不知道访问哪一个_a
return 0;
}
菱形继承的二义性(数据冗余)问题:
D继承了B和C,B和C继承了A,B和C中都有变量_a,但D访问 _a时,不知道是访问B中的 _a还是C中的 _a。
解决:菱形虚拟继承(virtual)
class A
{
public:
int _a;
};
class B :virtual public A
{
public:
int _b;
};
class C :virtual public A
{
public:
int _c;
};
class D :public B,public C
{
public:
int _d;
};
int main()
{
D d;
d._a = 1;
d._b = 2;
d._c = 3;
d._d = 4;
return 0;
}
这样就解决了菱形继承的二义性和数据冗余的问题。