虚函数:
一旦某个函数被声明成虚函数,则在他的派生类中它都是虚函数,所以子类的虚函数前 的virtual 可不写。
1函数重载:
同一个类中存在同名但是参数不同的函数,这样就是函数重载,函数重载在编译期间便能确定下来。
2、函数覆盖
函数覆盖也被称为函数重写(override),是子类重新定义基类虚函数的方法。
构成函数覆盖的条件:
(1)基类的函数必须是虚函数(virtual进行声明)
(2)发生覆盖的两个函数必须分别位于派生类和基类中
(3)函数名称和参数列表必须完全相同
由于c++态性是通过虚函数来实现的,所以函数覆盖总是和多态联系在一起,并且是程序在运行时才确定要调用的函数,
因此也成为动态绑定。
3、函数隐藏
函数隐藏是指子类中具有和基类同名的函数,但是并不考虑参数列表是否相同,从而在子类中隐藏了基类的同名函数。
有以下两种情况:
(1)子类函数和基类函数完全相同,只是基类的函数没有使用virtual关键字,此时基类的函数将被隐藏。
(2)子类函数和基类函数名字相同,但是参数列表不同,在这种情况下,无论基类的函数是否声明为virtual,基类的函数都将被隐藏。
class Base
{
public:
void print(){cout<<"Base";}
};
class Derived:public Base
{
public:
virtual void print(){cout<<"Derived";} //这种情况等同于没有virtual
};
{
public:
void print(){cout<<"Base";}
};
class Derived:public Base
{
public:
virtual void print(){cout<<"Derived";} //这种情况等同于没有virtual
};
这样称为隐藏 理由基类没有virtual!
因为是隐藏:
Base *point=new Derived();
point->print();
point->print();
output: Base
而:
Derived*point=new Derived();
point->print();
point->print();
output:Derived
class Base
{
public:
void print(){cout<<"Base";}
};
class Derived:public Base
{
public:
void print( int i){cout<<"Derived";} //这种情况等同于没有virtual
};
{
public:
void print(){cout<<"Base";}
};
class Derived:public Base
{
public:
void print( int i){cout<<"Derived";} //这种情况等同于没有virtual
};
Derived*point=new Derived();
point->print();
point->print();
error C2660: 'print' : function does not take 0 parameters
说明了print()被隐藏!
总结隐藏:
当基类和派生类 同名函数 参数列表不同时 ,或者基类不为虚函数,基类和派生类都相同。
这种情况下,派生类无法看到基类的那个函数
只用将派生类当成基类看待,才能看到那个函数。
这种情况等价于JAVA的重写!!!!!
class Base
{
public:
virtual void print(){cout<<"Base";}
};
class Derived:public Base
{
public:
virtual void print(){cout<<"Derived";} //virtual 可不写!
{
public:
virtual void print(){cout<<"Base";}
};
class Derived:public Base
{
public:
virtual void print(){cout<<"Derived";} //virtual 可不写!
};
这种情况 称为:函数覆盖!
Base *point=new Derived();
point->print();
point->print();
output :Derived
用基类的视角看派生类仍是派生类,说明了该函数已经完全被覆盖了。
在基类中及其派生类中都动态分配的内存空间时(动态建立对象),必须把析构函数定义为虚函数,实现撤消对象时的多态性。
根据赋值兼容规则可以用基类的指针指向派生类对象,如果由该指针撤销派生类对象,则必须将析构函数说明为虚函数,
实现多态性,自动调用派生类析构函数。我们总是要求将类设计成通用的,无论其他程序员怎样调用都必须保证不出错,
所以必须把析构函数定义为虚函数。在动态分配内存时所有C++的标准库函数都采用这种格式。
class person {
public:
virtual ~person(); //声明基类的的析构函数则派生类的析构函数都为虚函数
}
void main()
{
person *p = new student();
delete p;
//去掉virtual 就会看到问题!少析构了!!!
}
纯虚函数
是指被标明为不具体实现的虚拟成员函数。
定义一个基类时,会遇到无法定义基类中虚函数的具体实现,其实现依赖于不同的派生类。
virtual 返回类型 函数名(参数表)=0;
定义纯虚函数必须注意:
1 定义纯虚函数时,不能定义虚函数的实现部分。即使是函数体为空也不可以,函数体为空就可以执行,只是什么也不做就返回。而纯虚函数不能调用。
2 “=0”表明程序员将不定义该函数,函数声明是为派生类保留一个位置。“=0”本质上是将指向函数体的指针定为NULL。
3 在派生类中必须有重新定义的纯虚函数的函数体,这样的派生类才能用来定义对象。
1 定义纯虚函数时,不能定义虚函数的实现部分。即使是函数体为空也不可以,函数体为空就可以执行,只是什么也不做就返回。而纯虚函数不能调用。
2 “=0”表明程序员将不定义该函数,函数声明是为派生类保留一个位置。“=0”本质上是将指向函数体的指针定为NULL。
3 在派生类中必须有重新定义的纯虚函数的函数体,这样的派生类才能用来定义对象。