类的成员除了声明为 public 和 private 两种属性外,还可以声明为 protected (保护属性),并且派生类也可以以保护的方式继承基类。
当使用 protected 声明一个类的成员时,这个成员将不能被程序中不是类成员的其他代码访问。如下代码将产生编译错误:
[C++] 纯文本查看 复制代码
#include <iostream>
using namespace std;
class base {
protected:
int i, j; //对类 base 来说是私有的,但是派生类可以访问它们
public:
void set(int a, int b) { i = a; j = b; }
void show() { cout << i << " " << j << endl; }
};
int main()
{
base bc;
bc.set(4, 5);
cout << bc.i << endl; //错误,无法直接访问
return 0;
}
错误提示:protected.cc:7:6: error: ‘int base::i’ is protected
protected.cc:25:13: error: within this context
访问保护成员和访问私有成员一样,只能被同一个类中的其它成员访问;但是当保护成员被继承时,保护成员与私有成员有着本质不同。
当派生类使用 public 从基类继承时,基类中的保护成员也将成为派生类中的保护成员,在派生类中可以访问它们。如下面程序所示:
[C++] 纯文本查看 复制代码 #include <iostream>
using namespace std;
class base {
protected:
int i, j; //对类 base 来说是私有的,但是派生类可以访问它们
public:
void set(int a, int b) { i = a; j = b; }
void show() { cout << i << " " << j << endl; }
};
class derived : public base {
int k;
public:
//派生类可以访问类 base 的 i 和 j
void setk() { k = i*j; };
void showk() { cout << k << "\n"; }
};
int main()
{
derived ob;
ob.set(2, 3); //正确,派生类可以访问基类的成员变量 i 和 j
ob.show();
ob.setk(); //正确
ob.showk();
return 0;
}
运行输出:在上面程序中,derived 类以 public 形式继承了基类 base ,基类中的保护成员 i 和 j 也以同样的保护属性被继承到 derived 中来,所以 derived 类中的成员函数 setk() 可以直接访问 i 和 j 。但是,如果假设 base 中有一个私有成员 m ,那么在 setk() 函数里就不能直接访问这个 m ,如 k = i*j*m; 这样的语句就是错误的,访问 m 只能由 base 类中的成员函数来访问。对于这种情况可以打一个比方:
父亲(base 类)将一份放在保险箱里的礼物送给孩子(derived),同时把保险箱的钥匙(setk() 函数)交给他,那么孩子自然可以用这把钥匙打开这个保险箱获得属于他的礼物。
假设 m (base 类的私有成员变量) 是父亲的东西,它被父亲放在保险箱里,setm() 是 base 类的一个负责设置 m 变量的成员函数(打开保险箱的钥匙)。那么孩子如果要拿出父亲的东西,则必须用父亲的钥匙(setm()),而用刚才那把父亲送给你用来装礼物的保险箱的钥匙自然是无法打开的。
当派生类被用作另一个派生类的基类时,那么第一个派生类从初始基类中(以公有形式)继承的所有保护成员都将被第 2 个派生类再次继承,并作为第 2 个派生类的保护成员。如下程序所示:
[C++] 纯文本查看 复制代码
#include <iostream>
using namespace std;
class base {
protected:
int i, j; //对类 base 来说是私有的,但是派生类可以访问它们
public:
void set(int a, int b) { i = a; j = b; }
void show() { cout << i << " " << j << endl; }
};
class derived1 : public base {
int k;
public:
//派生类可以访问类 base 的 i 和 j
void setk() { k = i*j; };
void showk() { cout << k << "\n"; }
};
//i 和 j被直接从类 derived 中继承
class derived2 : public derived1 {
int m;
public:
void setm() { m = i - j; } //合法
void showm() { cout << m << endl; }
};
int main()
{
derived1 ob1;
derived2 ob2;
ob1.set(2, 3);
ob1.show();
ob1.setk();
ob1.showk();
ob2.set(4, 5);
ob2.show();
ob2.setk();
ob2.setm();
ob2.showk();
ob2.showm();
return 0;
}
运行输出:$ ./protected2
2 3
6
4 5
20
-1
当基类以私有方式被继承时,基类的保护成员将成为派生类的私有成员。如上面的示例中,若 base 以私有的方式被继承,那么 base 中的所有成员都将是 derived1 的私有成员,这也意味着 derived2 是不可以访问它们的。下面程序演示这种情况(该程序无法通过编译):
[C++] 纯文本查看 复制代码
#include <iostream>
using namespace std;
class base {
protected:
int i, j;
public:
void set(int a, int b) { i = a; j = b; }
void show() { cout << i << " " << j << endl; }
};
//base 中的所有成员都将成为 derived1 中的私有成员
class derived1 : private base {
int k;
public:
void setk() { k = i*j; }; //正确
void showk() { cout << k << "\n"; } //正确
};
class derived2 : public derived1 {
int m;
public:
void setm() { m = i - j; } //错误,非法访问,因为i和j是derived1的私有成员
void showm() { cout << m << endl; }
};
int main()
{
derived1 ob1;
derived2 ob2;
ob1.set(2, 3); //错误,不能直接调用
ob1.show(); //错误,不能直接调用
ob2.set(4, 5); //错误,不能直接调用
ob2.show(); //错误,不能直接调用
return 0;
}
另外,protected 控制符也可以用在结构中,但是不能用在联合中,因为联合不能从一个类中继承或者被继承。
protected 控制符可以放在类声明的任何位置,但习惯上会将它放在私有成员的声明之后,公有成员之前,如下形式:
[C++] 纯文本查看 复制代码
class class-name {
private members;
protected:
protected members;
public:
public members;
};
使用 protected 来继承基类
当一个基类以保护方式被继承时,基类的所有公有成员都将成为派生类的保护成员。下面程序不能通过编译,注释中说明了错误的原因:
[C++] 纯文本查看 复制代码
#include <iostream>
using namespace std;
class base {
int i;
protected:
int j;
public:
int k;
void seti(int a) { i = a; };
int geti() { return i; }
};
//以保护方式从 base 继承
class derived : protected base {
public:
void setj (int a) { j = a; } //正确, j 是保护成员
void setk (int a) { k = a; } //正确,k 也是保护成员
int getj() { return j; }
int getk() { return k; }
};
int main()
{
derived ob;
ob.seti(10); //错误:seti()是保护成员,derived 之外的代码无法访问,
//可以在 derived 中声明一个函数来调用该函数
cout << ob.geti(); //错误,理由同上
ob.k = 10; //错误,因为 k 是保护成员
ob.setk(10); //正确
ob.setj(20); //正确
cout << ob.getk() << ' '; //正确
cout << ob.getj() << endl; //正确
return 0;
}
总结 public, protected 和 private
当类的成员被声明为 public 时,它可以被程序的其它部分访问。
当类的成员被声明为 private 时,它只能由类中的成员访问,而且派生类也不能直接访问基类中的私有成员。
当成员被声明为 protected 时,它只能被类自身的成员或者派生类的成员访问。
当基类以 public 方式被继承时,它的共有成员成为派生类的公有成员,它的保护成员也成为派生类的保护成员。
当基类以 private 方式被继承时,它所有的公有成员和保护成员都将成为派生类的私有成员。
当基类以 protected 方式被继承时,它所有的公有成员和保护成员都将成为派生类的保护成员。
在所有的情况中,基类的私有成员仍然是基类的私有成员,不能被继承。 |