友元和继承
友元函数
原则上,类的私有和保护成员在声明它们所在的类之外是无法访问的。然而,这个规则不影响
友元。
友元是使用
friend
关键字声明的函数或类。
如果我们想将一个外部函数声明为类的友元,从而允许该函数访问类的私有和保护成员,我们可以在类内声明该外部函数的原型,并在其前面加上关键字
friend:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
// friend functions
#include <iostream>
using namespace std;
class CRectangle {
int width, height;
public:
void set_values (int, int);
int area () {return (width * height);}
friend CRectangle duplicate (CRectangle);
};
void CRectangle::set_values (int a, int b) {
width = a;
height = b;
}
CRectangle duplicate (CRectangle rectparam)
{
CRectangle rectres;
rectres.width = rectparam.width*2;
rectres.height = rectparam.height*2;
return (rectres);
}
int main () {
CRectangle rect, rectb;
rect.set_values (2,3);
rectb = duplicate (rect);
cout << rectb.area();
return 0;
}
|
24 |
要放回的字符的
重复函数是...的友元
CRectangle。在该函数内部,我们可以访问成员
宽度和
height来自不同类型的对象
CRectangle,这些是私有成员。请注意,在声明
duplicate()中,或者在后续使用
main()我们没有考虑
重复类的成员
CRectangle。它不是!它只是在不是成员的情况下访问其私有和保护成员。
友元函数可以用于,例如,在两个不同的类之间进行操作。通常,使用友元函数不符合面向对象编程的 منهج,因此,只要有可能,最好使用同一类的成员来执行操作。例如,在前面的例子中,将
duplicate()集成到类中
CRectangle.
友元类
正如我们可以定义友元函数一样,我们也可以将一个类定义为另一个类的友元,授予第一个类访问第二个类受保护和私有成员的权限。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
|
// friend class
#include <iostream>
using namespace std;
class CSquare;
class CRectangle {
int width, height;
public:
int area ()
{return (width * height);}
void convert (CSquare a);
};
class CSquare {
private:
int side;
public:
void set_side (int a)
{side=a;}
friend class CRectangle;
};
void CRectangle::convert (CSquare a) {
width = a.side;
height = a.side;
}
int main () {
CSquare sqr;
CRectangle rect;
sqr.set_side(4);
rect.convert(sqr);
cout << rect.area();
return 0;
}
|
16 |
在此示例中,我们已声明
CRectangle是...的友元
CSquare以便
CRectangle成员函数可以访问...的受保护和私有成员
CSquare,更具体地说,访问
CSquare::side,它描述了正方形的边长。
你可能还会在程序开头看到一些新东西:类的一个空声明
CSquare。这是必需的,因为在声明
CRectangle时,我们引用了 CSquare(在...中作为参数
convert())。的定义
CSquare稍后包含,所以如果我们不包含之前的空声明
CSquare,这个类在声明的定义中将不可见
CRectangle.
。请注意,朋友关系不是相互的,除非我们明确指定。在我们的例子中,
CRectangle被...视为友元类
CSquare,但
CRectangle不认为
CSquare是友元,所以
CRectangle可以访问...的受保护和私有成员
CSquare,但反之则不行。当然,如果需要,我们也可以声明
CSquare是...的友元
CRectangle。
友元关系的另一个特性是它们是
非传递的:朋友的朋友除非明确指定,否则不被认为是朋友。
类之间的继承
C++类的关键特性是继承。继承允许创建从其他类派生的类,因此它们会自动包含其“父类”的某些成员,再加上自己的成员。例如,我们假设我们想声明一系列描述多边形的类,例如我们的
CRectangle,或者像
CTriangle。它们具有某些共同的属性,例如都可以通过两个边来描述:高和底。
这可以在类的世界中用一个类来表示
CPolygon,从中我们将派生出另外两个类
CRectangle和
CTriangle.
该类
CPolygon将包含两种多边形共有的成员。在我们的例子中
宽度和
height。和
CRectangle和
CTriangle将是它的派生类,具有从一种多边形到另一种多边形的不同特定特征。
从其他类派生的类继承了基类的所有可访问成员。这意味着如果基类包含一个成员
A,我们将其派生到另一个带有成员的类
B,派生类将同时包含成员
A和
B.
为了从一个类派生另一个类,我们在派生类的声明中使用冒号(
:),使用以下格式
class derived_class_name: public base_class_name
{ /*...*/ };
其中
derived_class_name是派生类的名称,而
base_class_name是它所基于的类的名称。该
public访问说明符可以被其他任何访问说明符替换
protected和
private。此访问说明符限制了从基类继承的成员的可访问级别:可访问级别更高的成员将以该级别继承,而访问级别相等或更严格的成员将在派生类中保留其严格级别。
|
// derived classes
#include <iostream>
using namespace std;
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b;}
};
class CRectangle: public CPolygon {
public:
int area ()
{ return (width * height); }
};
class CTriangle: public CPolygon {
public:
int area ()
{ return (width * height / 2); }
};
int main () {
CRectangle rect;
CTriangle trgl;
rect.set_values (4,5);
trgl.set_values (4,5);
cout << rect.area() << endl;
cout << trgl.area() << endl;
return 0;
}
|
20
10 |
类的对象
CRectangle和
CTriangle每个都包含来自...的继承成员
CPolygon。这些是
宽度,
height和
set_values().
要放回的字符的
protected访问说明符类似于
private。它唯一的区别实际上发生在继承方面。当一个类继承自另一个类时,派生类的成员可以访问从基类继承的受保护成员,但不能访问其私有成员。
因为我们想要
宽度和
height可从派生类的成员访问
CRectangle和
CTriangle而不仅仅是通过...的成员
CPolygon,我们使用了
protected访问而不是
private.
。我们可以按如下方式总结不同访问类型根据谁可以访问它们
访问 | public | protected | private |
同一类的成员 | 是 | 是 | 是 |
派生类的成员 | 是 | 是 | 否 |
非成员 | 是 | 否 | 否 |
其中“非成员”代表任何来自类外部的访问,例如来自
main(),来自另一个类或来自一个函数。
在我们的例子中,继承的成员
CRectangle和
CTriangle具有与其基类中相同的访问权限
CPolygon:
1 2 3 4 5
|
CPolygon::width // protected access
CRectangle::width // protected access
CPolygon::set_values() // public access
CRectangle::set_values() // public access
|
这是因为我们使用了
public关键字在每个派生类上定义继承关系
1
|
class CRectangle: public CPolygon { ... }
|
这个
public关键字在冒号(
:)之后表示从其后的类(在本例中为
CPolygon)继承的成员的最可访问级别。由于
public是最可访问的级别,通过指定此关键字,派生类将以其在基类中的相同级别继承所有成员。
如果我们指定更严格的访问级别,例如
protected,基类的所有公共成员在派生类中被继承为受保护。而如果我们指定所有访问级别中最严格的
private,则所有基类成员都被私有继承。
例如,如果
daughter是从...派生的类
mother我们定义为
1
|
class daughter: protected mother;
|
这将设置
protected作为...成员的最大可访问级别
daughter它从...继承的
mother。也就是说,在...中公共的所有成员将成为...中的受保护成员
mother。当然,这不会限制
daughter声明其自己的公共成员。该最大可访问级别仅针对从...继承的成员设置
daughter如果未显式指定任何访问级别用于继承,则编译器会假定 classes declared with 的 private 关键字,而 struct classes declared with 的 public 关键字
mother.
class
类struct
关键字,以及 classes declared with 的 public 关键字.
从基类继承了什么?
原则上,派生类继承基类的所有成员,除了
- 其构造函数和析构函数
- 其 operator=() 成员
- 其友元
虽然基类的构造函数和析构函数本身不被继承,但在创建或销毁派生类的新对象时,其默认构造函数(即没有参数的构造函数)和析构函数总是会被调用。
如果基类没有默认构造函数,或者您希望在创建新的派生对象时调用重载构造函数,您可以在派生类的每个构造函数定义中指定它
derived_constructor_name (parameters) : base_constructor_name (parameters) {...}
例如:
|
// constructors and derived classes
#include <iostream>
using namespace std;
class mother {
public:
mother ()
{ cout << "mother: no parameters\n"; }
mother (int a)
{ cout << "mother: int parameter\n"; }
};
class daughter : public mother {
public:
daughter (int a)
{ cout << "daughter: int parameter\n\n"; }
};
class son : public mother {
public:
son (int a) : mother (a)
{ cout << "son: int parameter\n\n"; }
};
int main () {
daughter cynthia (0);
son daniel(0);
return 0;
}
|
mother: no parameters
daughter: int parameter
mother: int parameter
son: int parameter |
请注意,当创建新的...对象时调用...的构造函数,而创建...对象时调用...的构造函数之间的区别。
motherchild
daughterparent
child区别在于...的构造函数声明
daughter和
child:
1 2
|
daughter (int a) // nothing specified: call default
son (int a) : mother (a) // constructor specified: call this
|
多重继承
在 C++ 中,一个类完全可以继承一个以上的类。这可以通过在派生类声明中用逗号分隔不同的基类来实现。例如,如果我们有一个用于在屏幕上打印的特定类(
COutput),并且我们希望我们的类
CRectangle和
CTriangle除了...的成员外,还继承其成员
CPolygon我们可以写
1 2
|
class CRectangle: public CPolygon, public COutput;
class CTriangle: public CPolygon, public COutput;
|
这是完整的示例
|
// multiple inheritance
#include <iostream>
using namespace std;
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b;}
};
class COutput {
public:
void output (int i);
};
void COutput::output (int i) {
cout << i << endl;
}
class CRectangle: public CPolygon, public COutput {
public:
int area ()
{ return (width * height); }
};
class CTriangle: public CPolygon, public COutput {
public:
int area ()
{ return (width * height / 2); }
};
int main () {
CRectangle rect;
CTriangle trgl;
rect.set_values (4,5);
trgl.set_values (4,5);
rect.output (rect.area());
trgl.output (trgl.area());
return 0;
}
|
20
10 |