文章来源:http://blog.csdn.net/shift_wwx/article/details/78604016
本文是自己在学习了继承和派生,以及C++的多态性之后通过实例来说明继承和派生的过程,请大家不吝赐教。
1、继承的方式
继承方式有三种:public、private、protected。
具体的不做介绍,网上有很多文章。
注意的是,基类中的private成员是无法继承使用的,只能基类自己使用。protected成员也只能提供给派生类或者自己使用,对象是无法使用的。
2、多态方式
方式分两种:静态多态和动态多态。
静态多态指的是函数的重载和运算符的重载;
动态多态指的是虚函数。
虚函数的提出也就是为了多态性,而多态也是针对于基类指针或者基类的引用。对于实例对象而言就不存在这样的情况,直接引用即可。
3、实例
上面简单说明了下继承和派生,以及多态的产生,下面通过实例来确认下这些过程。
基类和派生类的code如下:
class Base {
public:
Base() : value(1) {}
~Base() {}
void print() {
cout << "This is Base class..." << endl;
cout << "value is " << value << endl;
}
int value;
};
class FromBase : public Base {
public:
FromBase() : value(2) {}
~FromBase() {}
void print() {
cout << "This is FromBase class..." << endl;
cout << "value is " << value << endl;
}
int value;
};
为了区分value的从属,在构造的时候分别对两个类中的value进行了初始化。
用来测试的code如下:
class Test1
{
public:
Test1();
~Test1();
void test();
};
Test1::Test1() {
cout << "class Test1" << endl;
}
Test1::~Test1() {
cout << "class Test1 destructor..." << endl;
}
void Test1::test() {
Base base;
FromBase fbase;
Base *p = NULL;
cout << "base's address is: " << &base << endl;
cout << "fbase's address is: " << &fbase << endl;
cout << "point p's address is: " << p << endl;
p = &base;
cout << "point p's address is: " << p << endl;
p->print();
cout << "point value's address is: " << &(p->value)
<< ", member value's address is: " << &base.value
<< ", value is "<< p->value << endl;
p = &fbase;
cout << "point p's address is: " << p << endl;
p->print();
cout << "point value's address is: " << &(p->value)
<< ", member value's address is: " << &fbase.value
<< ", value is " << p->value << endl;
}
运行结果如下:
通过结果可以看出:
- 两个对象创建成功,都能分配到内存;
- 通过基类指针调用的两个类中的成员函数print()其实都是基类的print()函数;
- 通过基类指针调用的两个类中的成员变量value其实都是基类的value;
对于多态性的认识和了解,我们将基类中的print()改成virtual属性,Base类改动后如下:
class Base {
public:
Base() : value(1) {}
~Base() {}
virtual void print() {
cout << "This is Base class..." << endl;
cout << "value is " << value << endl;
}
int value;
};
运行结果如下:
我们发现多态性真的生效了(完全废话,那必须生效)。可是value的值怎么办呢?多态性中没有成员变量的多态吧?
从log中可以看出:
Base中通过指针指向的value的地址和通过Base对象引用的value的地址是一样的,这一点也是毋庸置疑的。
FromBase中通过指针指向的value的地址和通过对象引用的value的地址并不一样,从这里我们可以知道派生类的内存大概分配方式。
总结:
通过基类指针可以通过virtual函数实现访问派生类的函数。
通过基类指针是无法访问派生类的成员变量。
基类的析构函数最好加个virtual,如果是指针delete的时候,会只会调用基类的析构,那如果派生类中有个成员指针,new之后需要在析构中delete,就没办法实现,最后出现OOM。
在对象的首地址和value地址中间隔了4个字节的空间,这个应该是放虚函数表指针的地方,对于32位系统应该是4个字节。