#include<iostream>
usingnamespace std;
class BASE
{
public:
BASE()=default;
BASE(int publicValue,int protectedVale,int privateValue)
{
this->publicValue = publicValue;
this->protectedValue = protectedVale;
this->privateValue = privateValue;
}
virtualint getPubValue(int value =0)
{
cout <<"BASE"<< endl;
publicValue = value;
return publicValue;
}
/**< 注意不是virtual函数 */
int getProValue()
{
return protectedValue;
}
public:
int publicValue;
protected:
int protectedValue;
private:
int privateValue;
};
class INHERT :public BASE
{
public:
INHERT(int pubValue,int proValue,int priValue):
BASE(pubValue, proValue, priValue)
{}
/**< 访问从父类继承的public成员 */
int getPubValue(int value =1) override
{
cout <<"INHERT"<< endl;
publicValue = value;
return publicValue;
}
/**< 访问从父类继承的protected成员 */
// int getProValue()
// {
// return protectedValue;
// }
/**< 从父类继承来的private成员,在子类中是不可访问的。*/
// int getPriValue()
// {
// return privateValue;
// }
/**< 将会隐藏基类中的同名函数,与参数类型或者参数的顺序无关 */
int getProValue(int value)
{
protectedValue = value;
return protectedValue;
}
/**< 通过添加using BASE::getProValue; 将基类所有getProValue函数的重载版本添加到派生类的作用域中去*/
/**< 在派生类中可以添加新的重载版本,或者覆盖已有的重载版本 */
using BASE::getProValue;
};
int main()
{
INHERT inhert(4,5,6);
BASE * base =&inhert;
/**< 虽然调用的是派生类的getPubValue()函数,但是由于该函数在基类和派生类中都带有默认值,所以该函数使用的是基类中的默认值 */
cout << base->getPubValue()<< endl;
/**< 由于在派生类中重新定义了getProValue函数,则从父类继承的getProValue()将会被隐藏*/
//cout << inhert.getProValue() << endl;
cout << inhert.getProValue(100)<< endl;
/**< 显式调用被隐藏函数 */
cout << inhert.BASE::getProValue()<< endl;
/**< 通过添加using BASE::getProValue; 将基类所有getProValue函数的重载版本添加到派生类的作用域中去*/
/**< 在派生类中可以添加新的重载版本,或者覆盖已有的重载版本 */
cout << inhert.getProValue()<< endl;
return0;
}
1 在C++中,有以下几个概念
重定义(redefine):派生类对基类的成员函数重新定义(即派生类定义了某个函数)该函数的名字与基类中的函数名字一样。
重载(overload):函数名字相同,但它的形参个数或者顺序(或者类型不同)注意不能靠返回类型来判断。
重写(override):派生类重定义基类的虚函数(即会覆盖基类的虚函数)。
如果在派生类中定义了一个与基类同名的函数,不管这个函数的参数列表是不是与基类中的函数相同,则这个同名的函数就会把基类中的所有这个同名的函数的所有重载版本都隐藏了,这时并不是在派生类中重载基类的同名成员函数,而是隐藏。
比如你的基类中有一个成员函数:void func(int i);而子类中又定义了一个void func();那么此时,基类中的void func(int i)就被自动隐藏了,子类对象不能直接调用它。
覆盖:(特征标全部相同的虚函数-原型相同)
如果派生类覆盖了基类中的成员函数或成员变量,则当派生类的对象调用该函数或变量时是调用的派生类中的版本,当用基类对象调用该函数或变量时是调用的基类中的版本。
2 怎样使用派生类的对象访问基类中被派生类覆盖或隐藏了的函数或变量
方法 1 使用作用域运算符:
在使用对象调用基类中的函数或变量时使用作用域运算符即语句 m.A::f(2),这时就能访问基类中的函数或变量版本。
注意,访问基类中被派生类覆盖了的成员变量只能用这种方法
方法 2 使用 using:
该方法只适用于被隐藏或覆盖的基类函数,在派生类的类声明中使用语句 using 把基类的名字包含进来(注意子类的重定义),比如using A::f;就是将基类中的函数f()的所有重载版本包含进来,重载版本被包含到子类之后,这些重载的函数版本就相当于是子类的一部分,这时就可以用派生类的对象直接调用被派生类隐藏了的基类版本,比如 m.f(2),但是使用这种语句还是没法调用基类在派生类中被覆盖了的基类的函数,比如 m.f()调用的是派生类中定义的函数f,要调用被覆盖的基类中的版本要使用语句m.A::f()才行。
在派生类的函数中调用基类中的成员变量和函数的方法:就是在函数中使用的被派生类覆盖的基类成员变量或函数
前用作域解析符加上基类的类名,即a::f()就是在派生类的函数中调用基类中被派生类覆盖了的函数f()的方法。
派生类以私有方式被继承时改变基类中的公有成员为公有的方法:
使用::作用域运算符,不提倡用这种方法,在派生类的 public 后面用作用域运算符把基类的 公有成员包含进来,这样基类的成员就会成为派生类中的公有成员了,注意如果是函数的 话后面不能加括号 ,如A::f;如果f是函数的话不能有括号。
使用using语句,现在一般用这种方法,也是在派生类的public使用using把基类成员包函进来,如using A::f。
3 如何设计类函数
-
对于希望子类重写的函数,也就是说基类可以提供自己的一份实现或者不提供实现,但是子类必须拥有自己的实现。一般采用虚函数或者纯虚函数;
-
对于一般的成员函数,在子类中不要进行重新定义,一般继承父类的实现即可;