9.3 继承机制下的访问控制
对在派生类中访问继承下来的成员这个问题需要更仔细地审视。考虑一下派生类中基类private成员的状态。
在上一个示例中,我们有很好的理由选择拥有public数据成员的CBox类版本,而非后来开发的、拥有private数据成员的更安全的版本。原因在于虽然基类的private数据成员也是派生类的成员,但它们在派生类中仍然是基类所私有的,因此添加到派生类的成员函数不能访问它们。只有通过不属于基类private部分的基类函数成员,才能在派生类中访问它们。我们可以非常简单地证实这一点,方法是将CBox类的所有数据成员修改为private,然后在派生类CCandyBox中添加一个Volume()函数,这样类定义将如下所示:
- // Version of the classes that will not compile
- class CBox
- {
- public:
- CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0):
- m_Length(lv), m_Width(wv), m_Height(hv){}
-
- private:
- double m_Length;
- double m_Width;
- double m_Height;
- };
-
- class CCandyBox: public CBox
- {
- public:
- char* m_Contents;
-
- // Function to calculate the volume of a CCandyBox object
- double Volume() const // Error - members not accessible
- { return m_Length*m_Width*m_Height; }
-
- CCandyBox(char* str = "Candy") // Constructor
- {
- m_Contents = new char[ strlen(str) + 1 ];
- strcpy_s(m_Contents, strlen(str) + 1, str);
- }
-
- ~CCandyBox() // Destructor
- { delete[] m_Contents; }
- };
使用这些类的程序不能编译。CCandyBox类中的Volume()函数企图访问基类的private成员,这是非法的。
试一试:访问基类的私有成员
但使用基类的Volume()函数是合法的,因此如果我们将Volume()函数的定义移到基类CBox的public部分,则不仅该程序能够编译,而且还可以使用该函数来获得CCandyBox对象的体积。新建一个WIN32项目Ex9_02,在Box.h文件中输入下面的内容:
- // Box.h in Ex9_02
- #pragma once
-
- class CBox
- {
- public:
- CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0):
- m_Length(lv), m_Width(wv), m_Height(hv){}
-
- //Function to calculate the volume of a CBox object
- double Volume() const
- { return m_Length*m_Width*m_Height; }
-
- private:
- double m_Length;
- double m_Width;
- double m_Height;
- };
该项目中CandyBox.h头文件的内容如下:
- // Header file CandyBox.h in project Ex9_02
- #pragma once
- #include "Box.h"
- class CCandyBox: public CBox
- {
- public:
- char* m_Contents;
-
- CCandyBox(char* str = "Candy") // Constructor
- {
- m_Contents = new char[ strlen(str) + 1 ];
- strcpy_s(m_Contents, strlen(str) + 1, str);
- }
-
- ~CCandyBox() // Destructor
- { delete[] m_Contents; };
- };
本项目的Ex9_02.cpp文件包含以下内容:
- // Ex9_02.cpp
- // Using a function inherited from a base class
- #include <iostream> // For stream I/O
- #include <cstring> // For strlen() and strcpy()
- #include "CandyBox.h" // For CBox and CCandyBox
- using std::cout;
- using std::endl;
-
- int main()
- {
- CBox myBox(4.0,3.0,2.0); // Create CBox object
- CCandyBox myCandyBox;
- CCandyBox myMintBox("Wafer Thin Mints");
// Create CCandyBox object -
- cout << endl
- << "myBox occupies " << sizeof myBox // Show how much memory
- << " bytes" << endl // the objects require
- << "myCandyBox occupies " << sizeof myCandyBox
- << " bytes" << endl
- << "myMintBox occupies " << sizeof myMintBox
- << " bytes";
- cout << endl
- << "myMintBox volume is " << myMintBox.Volume();
// Get volume of a -
// CCandyBox object - cout << endl;
- return 0;
- }
该示例产生下面的输出:
- myBox occupies 24 bytes
- myCandyBox occupies 32 bytes
- myMintBox occupies 32 bytes
- myMintBox volume is 1
示例说明
增加的输出是最后一行,该行显示出现在属于基类public部分的Volume()函数产生的数值。在派生类内部,该函数在派生类中对基类继承的成员进行操作。Volume()函数完全是派生类的成员,因此可以自由地处理派生类的对象。
派生类对象的体积值是1,因为在创建CCandyBox对象时,为了创建该对象的基类部分而首先调用了默认构造函数CBox(),该函数将默认的CBox尺寸设定为1。