数据抽象(data abstraction),继承(inheritance)与动态绑定(dynamic binding)是面向对象编程(object-oriented programming)的三大核心思想(key ideas)。
数据抽象好理解,就是使得我们将类的接口与实现分离
继承与动态绑定在使用上是相关的
这里我们注意几点:
1.继承类(derived class)需要在自己内部(就是class{...}内部)有它打算自己实现的(defile it self)虚函数(virtual function) 的声明(declaration).这句话听起来好像是废话,我当然要声明了 ,但我感觉想表达的重点是这样的:你需要自己内部(own class body)声明,你想修改的基类function,当然基类中你想要修改的function 都是virtual function ,如果没有内部声明基类中的部分virtual function ,那么对于继承类来讲就相当于无修改直接继承这个函数(inherit without change)
2.动态绑定dynamic binding or run-time binding
C++ primer原文是这样说的:
In C++ ,dynamic binding happens when a virtual funtion is called through a reference(or a pointer)to a base class
.在C++中,动态绑定发生的场景的两个条件: virtual funtion 和 a reference(or a pointer)to a base class 。
首先你调用的要是一个虚函数,其次是引用或者指针调用的。
所以在实际工程中,要实现动态绑定,我们传的参数都是用引用或者指针。
3.作为基类,它的function ,需要区分为期望继承类override的(即继承类自己define it self的)和期望继承类能够 无修改直接继承的(inherit without change)。
对于期望继承类override的function,我们要在基类中,将这项function 定义为virtual ,具体操作就是在声明前加上关键字virtual , 也就是所谓的将这个function定义为了虚函数。就像2中说讲的,我们使用引用或者指针call 虚函数,实现动态绑定
A function this is declared as virtual in the base class is implictly virtual in derived class as well.
4.一个在基类中声明的虚函数,在继承类中会隐式地(implicitly)为virtual
下面我们举几个例子说明,并观察结果
例1:
class A{
public :
void Print()
{
printf("A\n");
}
};
class B :public A{
public:
void Print()
{
printf("B\n");
}
};
void Show(A &a)
{
a.Print();
}
int _tmain(int argc, _TCHAR* argv[])
{
A a;
B b;
Show(a);
Show(b);
return 0;
}
运行的结果为:
A
A
因为基类A 中的Print函数并没有声明为virtual ,所以无法实现动态绑定,所以a.Print都是调用A的function 。
例2:
不同于例1的地方就是在A 的Print 函数前加上virtual keyword
class A{
public :
virtual void Print()
{
printf("A\n");
}
};
class B :public A{
public:
void Print()
{
printf("B\n");
}
};
void Show(A &a)
{
a.Print();
}
int _tmain(int argc, _TCHAR* argv[])
{
A a;
B b;
Show(a);
Show(b);
return 0;
}
运行的结果为:
A
B
base class A函数Print 已经被声明为virtual ,可以进行动态绑定,且Show中的传入参数a为引用。在调用Show(b)时,这时候Show里面的a.Print,调用的其实是class B中的Print例3:
不同于例2的地方是show函数的传入参数不用引用 而是普通形参
class A{
public :
virtual void Print()
{
printf("A\n");
}
};
class B :public A{
public:
void Print()
{
printf("B\n");
}
};
void Show(A a)
{
a.Print();
}
int _tmain(int argc, _TCHAR* argv[])
{
A a;
B b;
Show(a);
Show(b);
return 0;
}
运行的结果为:
A
A
结果与例2不同,这是因为Show的传入参数不是引用或者指针,这样,show中的a,一定是A类型 ,无法改变,脱离的动态二字。具体原因就是传参类型不同,这里需要理解传参的机制是如何的,其实引用是变相的传递指针,只是比指针更加安全,不容易引起崩溃问题,具体原因请看引用的原理。
动态绑定时,调用时的类都是较底层类型,就是在这个继承层次(hierarchy)中,都是 较底层类型(基类) 动态调用 较高层类型(继承类)
今天写到这里,后面继续补充...