如果没有继承,类只是具有一些相关行为的数据结构,这只是对过程语言的一大改进,而继承则开辟了完全不同的新天地。通过继承,可以在已有类的基础上创建新类。这样,类就成为可重用和可扩展的组件。博主的《漫谈继承技术》系列博文将讲述各种利用继承功能的方法。学习继承的语法,和利用继承的一些复制技术。本篇博文先给大家介绍一下重写方法时的一些特殊情况,希望对大家加深对继承技术的理解有一定的帮助。
重写方法时的特殊情况
静态基类方法
在C++中,不能重写静态方法。方法不可能既是静态的又是虚拟的。如果派生类中存在的静态方法与基类中的静态方法同名,实际上这是两个独立的方法。举个栗子。
#include <iostream>
using namespacestd;
//基类super
class super
{
public:
virtual~super(){}
staticvoidstaticFun();
};
//基类super的静态方法
void super::staticFun()
{
cout<< "call: "<< __FUNCTION__ << endl;
}
//派生类sub继承自super
class sub: public super
{
public:
virtual~sub(){}
staticvoidstaticFun();
};
//派生类sub的静态方法,方法名称和参数列表同基类完全一样
void sub::staticFun()
{
cout<< "call: "<< __FUNCTION__ << endl;
}
int main(intargc,char**argv)
{
sub mysub = sub();
super &ref = mysub;
super *ptr = &mysub;
super::staticFun();
sub::staticFun();
mysub.staticFun();
ref.staticFun();
ptr->staticFun();
return0;
}
程序运行结果:
静态方法属于定义它的类所有,而不属于特定的对象。当类中的方法调用静态方法时,所调用的版本是通常的名称解析来决定的。当使用对象、指针或引用调用类的静态方法时,实际上并不涉及到调调用,只是用来判断编译时的类型,真正起作用的是类型信息。
private或protected基类方法
方法的访问说明符会判断谁可以调用这些方法,派生类无法调用基类的private方法(基类的private方法对于派生类不可见),但可以重写这些方法。
#include <iostream>
using namespacestd;
//基类super
class super
{
public:
virtual~super(){}
virtualvoidcallshow() const;
private:
virtualvoidshow() const;
};
void super::callshow()const
{
cout<< "call: "<< __FUNCTION__ << "->";
show();
}
void super::show()const
{
cout<< "call: "<< __FUNCTION__ << endl;
}
//派生类sub继承自super
class sub: public super
{
public:
virtual~sub(){}
private:
//派生类重写基类的private方法
virtualvoidshow() const override;
};
void sub::show()const
{
cout<< "call: "<< __FUNCTION__ << endl;
}
int main(intargc,char**argv)
{
sub mysub = sub();
super *ptr = &mysub;
//调用基类的public方法
ptr->callshow();
return0;
}
程序运行结果:
注意到了么?callshow调用的是派生类的show方法。通过重写这个private方法,派生类完全修改了没有更改的现有基类public方法的行为。重写private或protected方法可以在不做重大改动的情况下改变类的某些特性。对了,差点忘了,注意Java和C#仅允许重写public和protected方法,不能重写private方法。
基类方法具有默认参数
派生类与基类可以具有不同的默认参数,但使用的参数仅取决于声明的变量类型,而不是底层的对象。举个栗子。
#include <iostream>
using namespacestd;
//基类super
class super
{
public:
virtual~super(){}
virtualvoidshow(int nValue) const;
};
//给基类show方法指定默认参数
void super::show(intnValue= 10) const
{
cout<< "call: "<< __FUNCTION__ << " nValue = "<< nValue << endl;
}
//派生类sub继承自super
class sub: public super
{
public:
virtual~sub(){}
virtualvoidshow(int nValue) constoverride;
};
//给派生类show方法指定默认参数
void sub::show(intnValue= 20) const
{
cout<< "call: "<< __FUNCTION__ << " nValue = "<< nValue << endl;
}
int main(intargc,char**argv)
{
sub mysub = sub();
super mysuper = super();
super *ptr = &mysub;
//通过派生类对象调用show方法
mysub.show();
//通过基类对象调用show方法
mysuper.show();
//通过指向派生类对象的基类指针调用show方法
ptr->show();
return0;
}
程序运行结果:
从程序运行结果可以看出,如果sub对象调用show(),将执行sub版本的show(),默认参数为20。如果super对象调用show(),将执行super版本的show(),默认参数为10。然而,如果使用实际指向sub对象的super指针或者super引用调用show(),将执行sub版本的show(),但使用super的默认参数10。
C++根据描述对象的表达式类型在编译时绑定默认参数(也就是我们常说的静态绑定),而不是根据实际的对象类型绑定参数。在C++中,默认参数不会被“继承”。当重写具有默认参数的方法时,也应该提供默认参数,这个参数的值应该与基类版本相同(这里是为了给大家举个栗子,所有默认参数值取得不同)。建议使用符号常量做默认值,这样可以在派生类中使用同一个符号常量。
派生类方法具有不同的访问级别
在派生类继承基类时,可以采用两种方法来修改方法的访问级别——可以加强限制,也可以放宽限制。
放宽限制
#include <iostream>
using namespacestd;
//基类super
class super
{
public:
super(){}
virtual~super(){}
protected:
//基类protected方法
virtualvoidshow(const std::string&str) const;
};
void super::show(conststd::string &str)const
{
cout<< __FUNCTION__ << ": "<< str << endl;
}
//派生类sub继承基类super
class subfinal: public super
{
public:
sub(){}
virtual~sub(){}
//以public访问说明重写show方法,放宽限制
virtualvoidshow(const std::string&str) const override;
//提供访问基类show方法的接口
voidcallshow(const std::string&str) const;
};
void sub::show(conststd::string &str)const
{
cout<< __FUNCTION__ << ": "<< str << endl;
}
void sub::callshow(conststd::string &str)const
{
cout<< __FUNCTION__ << "->";
__super::show(str);
}
int main()
{
//用基类指针指向派生类对象
sub *sp = new sub();
//调用的是派生类的show方法,基类方法被隐藏
sp->show("hello");
//通过派生类的public接口调用基类的protected方法
sp->callshow("hello");
//释放资源
deletesp;
//将基类指针置为nullptr,避免野指针
sp = nullptr;
return0;
}
程序运行结果:
上例中提供了两种访问show函数的方法,一种是重写基类的show方法,另一种是在派生类中提供调用基类show方法的接口。
加强限制
#include <iostream>
using namespacestd;
//基类super
class super
{
public:
super(){}
virtual~super(){}
//基类public方法
virtualvoidshow(const std::string&str) const;
};
void super::show(conststd::string &str)const
{
cout<< __FUNCTION__ << ": "<< str << endl;
}
//派生类sub继承基类super
class subfinal: public super
{
public:
sub(){}
virtual~sub(){}
protected:
//以protected访问说明重写show方法,加强限制
virtualvoidshow(const std::string&str) const override;
};
void sub::show(conststd::string &str)const
{
cout<< __FUNCTION__ << ": "<< str << endl;
}
int main()
{
sub mysub = sub();
//用基类指针指向派生类对象
super *sp = &mysub;
//mysub.show();
//通过基类类的public接口调用派生类的protected方法
sp->show("hello");
return0;
}
程序运行结果:
上例程序中,当我们通过sp访问show方法时,无法限制访问基类的public方法,再结合多态性,将调用派生类的protected方法。
如果想了解更多关于继承技术相关的知识,请关注博主《漫谈继承技术》系列博文,相信你能够在那里寻找到更多有助你快速成长和深入你对继承相关的知识和一些复制的技术理解和掌握。