在进行下面的说明之前,先说一下什么是类型兼容规则:类型的兼容规则是指在需要基类对象的任何地方,都可以用公有派生类的对象来替代。这样公有派生类实际就具备了基类的所有功能,凡是基类能够解决的问题,公有派生类都可以解决,类型兼容规则中所指的替代包括以下的情况:
。派生类的对象可以赋值给基类的对象
。派生类的对象可以初始化基类的引用
。派生类对象的地址可以赋给指向基类的引用
根据类型兼容规则,可以使用派生类的对象代替基类的对象,如果用基类类型的指针指向派生类对象,就可以通过这个指针访问给对象,问题是访问到的只是从基类继承来的同名成员。如果需要通过基类的指针指向派生类的对象,并访问某个同名的成员,那么就要在基类中将这个同名的成员函数说明为虚函数。
# include <iostream.h>
class A
{
public:
virtual void play(){cout<<"A::play()"<<endl;}//使用virtual关键字此函数为虚函数,否则不为虚函数
};
class B:public A
{
void play(){cout<<"B::play()"<<endl;}
};
class C:public B
{
void play(){cout<<"C::play()"<<endl;}
};
void main()
{
A *ap;
B b;
C c;
ap=&b;
ap->play();
ap=&c;
ap->play();
}
program out:
如果类A不定义为虚函数:
A::play()
A::play()
如果类定义为虚函数
B:play()
C:play()
下面说明什么是虚基类,在说明虚基类之前先说明类的同名覆盖原则,同名覆盖原则是指在没有虚函数的情况下,如果某派生类的多个基类拥有同名的成员,同时,派生类又新增这样的同名成员,在这种情况下,派生类成员将隐藏所有基类的同名成员。举例:
#include <iostream.h>
class A
{
public:
void play(){cout<<"A::play()"<<endl;
};
class B:public A
{
public:
void play(){cout<<"B::Play()"<<endl;
};
void main()
{
B b;
b.play(); //派生类对象b的同名成员play()覆盖了基类的play()成员
b.A::paly(); //要想访问基类的成员用b.A::play()
}
那么什么是虚基类呢?
当某个派生类的部分或全部直接基类是从另一个共同的基类派生而来时,在这些直接基类中从上一级共同基类继承来的成员就拥有相同的名称,因此派生类中也就会产生同名现象,在派生类的对象中,这些同名数据成员在内存中同时拥有多个拷贝,同名函数名就有多个映射,对这种类型的同名成员也要使用作用域分辨符来惟一标识,而且用直接基类来限定,但是我们有没有别的办法让派生类中同名成员有一个拷贝呢,回答是,有。我们可以将共同基类设置为虚基类,这时从不同的路径继承下来的同名成员在内存就只有一个拷贝,同一个函数也只有一个映射。
#include <iostream.h>
class A
{
public;
int a;
void play(){cout<<"A::play()"<<endl;}
};
class B1:virtual publc A //关键字virtual的作用是定义类A为虚基类
{
publci:
int b1;
};
class B2:virtual public A //关键字virtual的作用是定义类A为虚基类
{
public:
int b2;
};
class C:publci B1 ,public B2
{
public:
int c;
void play(){cout<<"C::play()"<<endl;}
};
void main()
{
C c;
c.play();
}
program out:
A::paly()
。派生类的对象可以赋值给基类的对象
。派生类的对象可以初始化基类的引用
。派生类对象的地址可以赋给指向基类的引用
根据类型兼容规则,可以使用派生类的对象代替基类的对象,如果用基类类型的指针指向派生类对象,就可以通过这个指针访问给对象,问题是访问到的只是从基类继承来的同名成员。如果需要通过基类的指针指向派生类的对象,并访问某个同名的成员,那么就要在基类中将这个同名的成员函数说明为虚函数。
# include <iostream.h>
class A
{
public:
virtual void play(){cout<<"A::play()"<<endl;}//使用virtual关键字此函数为虚函数,否则不为虚函数
};
class B:public A
{
void play(){cout<<"B::play()"<<endl;}
};
class C:public B
{
void play(){cout<<"C::play()"<<endl;}
};
void main()
{
A *ap;
B b;
C c;
ap=&b;
ap->play();
ap=&c;
ap->play();
}
program out:
如果类A不定义为虚函数:
A::play()
A::play()
如果类定义为虚函数
B:play()
C:play()
下面说明什么是虚基类,在说明虚基类之前先说明类的同名覆盖原则,同名覆盖原则是指在没有虚函数的情况下,如果某派生类的多个基类拥有同名的成员,同时,派生类又新增这样的同名成员,在这种情况下,派生类成员将隐藏所有基类的同名成员。举例:
#include <iostream.h>
class A
{
public:
void play(){cout<<"A::play()"<<endl;
};
class B:public A
{
public:
void play(){cout<<"B::Play()"<<endl;
};
void main()
{
B b;
b.play(); //派生类对象b的同名成员play()覆盖了基类的play()成员
b.A::paly(); //要想访问基类的成员用b.A::play()
}
那么什么是虚基类呢?
当某个派生类的部分或全部直接基类是从另一个共同的基类派生而来时,在这些直接基类中从上一级共同基类继承来的成员就拥有相同的名称,因此派生类中也就会产生同名现象,在派生类的对象中,这些同名数据成员在内存中同时拥有多个拷贝,同名函数名就有多个映射,对这种类型的同名成员也要使用作用域分辨符来惟一标识,而且用直接基类来限定,但是我们有没有别的办法让派生类中同名成员有一个拷贝呢,回答是,有。我们可以将共同基类设置为虚基类,这时从不同的路径继承下来的同名成员在内存就只有一个拷贝,同一个函数也只有一个映射。
#include <iostream.h>
class A
{
public;
int a;
void play(){cout<<"A::play()"<<endl;}
};
class B1:virtual publc A //关键字virtual的作用是定义类A为虚基类
{
publci:
int b1;
};
class B2:virtual public A //关键字virtual的作用是定义类A为虚基类
{
public:
int b2;
};
class C:publci B1 ,public B2
{
public:
int c;
void play(){cout<<"C::play()"<<endl;}
};
void main()
{
C c;
c.play();
}
program out:
A::paly()