面向对象的主要目的之一是提供可重用的代码。面向对象主要包括封装、继承、多态等特性,在做项目的时候碰到的最多的应该是继承了,但是总是对继承的感觉是模模糊糊的,不知道什么时候用哪种继承,所以我再次翻阅了c++ primer以及effictive c++等书籍,将关于c++中类继承的相关知识完整梳理了一下。
继承就是从已有的类派生出新的类,派生类继承了原有类(基类)的特征:属性和方法。c++中的类有三种访问权限:公有(public )、私有(private)以及保护(protected),而c++的类继承也分为公有继承、私有继承、保护继承。
公有继承:是最常用的一种继承方式,建立一种is-a关系:派生类对象也是一个基类对象;可以对基类对象执行的任何操作,也可以对派生类对象执行。
公有继承下基类中的私有成员只能是基类自己成员函数能够访问,派生类成员函数无权直接访问;基类中的保护成员则可以被派生类成员函数可以访问,但是不能直接访问;基类中的公有成员则派生类对象可以直接访问。
示例如下:
基类:BaseClass
class BaseClass
{
public:
BaseClass(void)
{
m_nprivateValue = 10;
m_nprotectedValue = 20;
m_npublicValue = 30;
}
~BaseClass(void)
{
}
private:
int m_nprivateValue;
protected:
int m_nprotectedValue;
public:
int m_npublicValue;
public:
void show()
{
cout<<"基类成员函数访问私有成员m_nprivateValue="<<m_nprivateValue<<"\n";
cout<<"基类成员函数访问保护成员m_nprotectedValue="<<m_nprotectedValue<<"\n";
cout<<"基类成员函数访问公有成员m_npublicValue="<<m_npublicValue<<"\n";
}
};
派生类:DeriveClass
class DeriveClass :
public BaseClass
{
public:
DeriveClass(void)
{
m_nprotectedValue = 40;
m_npublicValue = 50;
}
~DeriveClass(void)
{}
public:
void displayValue()
{
cout<<"派生类成员函数访问基类的私有成员m_nprivateValue="<<m_nprivateValue<<"\n";//error C2248:cannot access private member declared in class 'BaseClass'
cout<<"派生类成员函数访问基类的私有成员m_nprotectedValue="<<m_nprotectedValue<<"\n";
cout<<"派生类成员函数访问基类的公有成员m_npublicValue="<<m_npublicValue<<"\n";
}
};
主程序main:
int main()
{
BaseClass* testBase = new BaseClass;
testBase->show();
cout<<"基类对象直接访问基类的私有成员m_nprivateValue="<<testBase->m_nprivateValue<<"\n"; //error C2248:cannot access private member declared in class 'BaseClass'
cout<<"基类对象直接访问基类的保护成员m_nprotectedValue="<<testBase->m_nprotectedValue<<"\n";//error C2248: cannot access protected member declared in class 'BaseClass'
cout<<"基类对象直接访问基类的公有成员m_npublicValue="<<testBase->m_npublicValue<<"\n";
DeriveClass* test = new DeriveClass;
test->displayValue();
cout<<"派生对象直接访问基类的私有成员m_nprivateValue="<<test->m_nprivateValue<<"\n";//error C2248:cannot access private member declared in class 'BaseClass'
cout<<"派生对象直接访问基类的保护成员m_nprotectedValue="<<test->m_nprotectedValue<<"\n";//error C2248: cannot access protected member declared in class 'BaseClass'
cout<<"派生对象直接访问基类的公有成员m_npublicValue="<<test->m_npublicValue<<"\n";
system("pause");
return 0;
}
使用VS编译时如上面所示,会出现五个访问权限的错误。
私有继承:基类的公有成员和保护成员都将成为派生类的私有成员。基类方法不会成为派生对象公有接口的一部分。但是派生类的成员函数可以访问或使用它们。
私有继承中则不管基类成员的访问权限是什么,都会转化为派生类的私有成员,也就是只能派生类的成员函数可以访问。这个就是has-a的关系,相当于派生对象有一个基类对象似得(类似组合关系)。
将上述代码中
class DeriveClass :
public BaseClass
改为
class DeriveClass:
private BaseClass
那么代码
cout<<"派生对象直接访问基类的公有成员m_npublicValue="<<test->m_npublicValue<<"\n"; //error C2247: 'BaseClass::m_npublicValue' not accessible because 'DeriveClass' uses 'private' to inherit from 'BaseClass'
也会编译出错,提示无访问权限。
保护继承:与私有继承相似,保护继承使得基类的公有成员和保护成员都将变成派生类的保护成员。但是派生类对象以及派生的继承类(第三代类)对象均可以访问基类的 公有或保护成员。
保护继承中唯一与私有继承不一样的是对于第三代以及以下的派生类而言都可以使用成员函数直接访问(私有继承则是只能是第一代派生类可以通过成员函数直接访问)。
将代码中
class DeriveClass :public BaseClass
改为
class DeriveClass:
protected BaseClass
在第一代继承中和私有继承表现一样。
cout<<"派生对象直接访问基类的公有成员m_npublicValue="<<test->m_npublicValue<<"\n"; //error C2247: 'BaseClass::m_npublicValue' not accessible because 'DeriveClass' uses 'protected' to inherit from 'BaseClass'
class Derive_DeriveClass :
protected DeriveClass
{
public:
Derive_DeriveClass(void)
{
m_nprotectedValue = 60;
m_npublicValue = 70;
}
~Derive_DeriveClass(void)
{}
public:
void displayValueex()
{
cout<<"二代派生类成员函数访问基类的私有成员m_nprivateValue="<<m_nprivateValue<<"\n";
cout<<"二代派生类成员函数访问基类的私有成员m_nprotectedValue="<<m_nprotectedValue<<"\n";
cout<<"二代派生类成员函数访问基类的公有成员m_npublicValue="<<m_npublicValue<<"\n";
}
};
如果都是两次继承都是保护继承,那么在displayValueex()方法中只有m_nprivateValue不可以访问。
如果第一次继承是保护继承,第二次继承是私有继承,那么在displayValueex()方法中只有m_nprivateValue不可以访问。
如果第一次继承私有继承,不管第二次继承是是什么继承,那么在displayValueex()方法中三个成员都不可以访问。
在我们一般编写程序的过程中,用的最多的是公有继承,少量会使用私有继承,保护继承的使用则更少。但是理清这三种继承的用法之后,我们在编写代码的时候就敢于善于使用私有继承或者保护继承,扩展我们的思路。希望自己通过这次总结梳理能真正将三个继承融汇。
继承的类型就先梳理到这里啦,下一节准备梳理一下虚函数在继承中的作用。