原地址: http://www.cplusplus.com/doc/tutorial/inheritance/

Friend functions

In principle, private and protected members of a class cannot be accessed from outside the same class in which they are declared. However, this rule does not apply to "friends".

 

Friends are functions or classes declared with the friend keyword.

 

A non-member function can access the private and protected members of a class if it is declared a friend of that class. That is done by including a declaration of this external function within the class, and preceding it with the keyword friend:

 

// friend functions

#include<iostream>

usingnamespace std;

 

classRectangle {

    intwidth, height;

  public:

    Rectangle() {}

    Rectangle (int x, int y) : width(x), height(y) {}

    int area() {returnwidth * height;}

    friendRectangle duplicate (constRectangle&);

};

 

Rectangle duplicate (constRectangle& param)

{

  Rectangle res;

  res.width = param.width*2;

  res.height = param.height*2;

  return res;

}

 

int main () {

  Rectangle foo;

  Rectangle bar (2,3);

  foo = duplicate (bar);

  cout << foo.area() << '\n';

  return 0;

}

 

you should get

 

24

 

 

The duplicate function is a friend of class Rectangle. Therefore, function duplicate is able to access the members width and height (which are private) of different objects of type Rectangle. Notice though that neither in the declaration of duplicate nor in its later use in main, member function duplicate is considered a member of class Rectangle. It isn't! It simply has access to its private and protected members without being a member.

 

Typical use cases of friend functions are operations that are conducted between two different classes accessing private or protected members of both. 

 

Friend classes

Similar to friend functions, a friend class is a class whose members have access to the private or protected members of another class:

 

// friend class

#include<iostream>

usingnamespace std;

 

classSquare;

 

classRectangle {

    intwidth, height;

  public:

    int area ()

      {return (width * height);}

    void convert (Square a);

};

 

classSquare {

  friendclassRectangle;

  private:

    intside;

  public:

    Square (int a) : side(a) {}

};

 

void Rectangle::convert (Square a) {

  width = a.side;

  height = a.side;

}

  

int main () {

  Rectangle rect;

  Square sqr (4);

  rect.convert(sqr);

  cout << rect.area();

  return 0;

}

 

you should get

 

16

 

 

In this example, class Rectangle is a friend of class Square allowing Rectangle's member functions to access private and protected members of Square. More concretely, Rectangle accesses the member variable Square::side, which describes the side of the square.

 

There is something else new in this example: at the beginning of the program, there is an empty declaration of class Square. This is necessary because class Rectangle uses Square (as a parameter in member convert), and Square uses Rectangle (declaring it a friend). 

 

Friendships are never corresponded unless specified: In our example, Rectangle is considered a friend class by Square, but Square is not considered a friend by Rectangle. Therefore, the member functions of Rectangle can access the protected and private members of Square but not the other way around. Of course, Square could also be declared friend of Rectangle, if needed, granting such an access.

 

Another property of friendships is that they are not transitive: The friend of a friend is not considered a friend unless explicitly specified.

 

Inheritance between classes

Classes in C++ can be extended, creating new classes which retain characteristics of the base class. This process, known as inheritance, involves a base class and a derived class: The derived class inherits the members of the base class, on top of which it can adds its own members.

 

For example, let's imagine a series of classes to describe two kinds of polygons: rectangles and triangles. These two polygons have certain common properties, such as the values needed to calculate their areas: they both can be described simply with a height and a width (or base).

 

This could be represented in the world of classes with a class Polygon from which we would derive the two other ones: Rectangle and Triangle:

 

 

The Polygon class would contain members that are common for both types of polygon. In our case: width and height. And Rectangle and Triangle would be its derived classes, with specific features that are different from one type of polygon to the other.

 

Classes that are derived from others inherit all the accessible members of the base class. That means that if a base class includes a member A and we derive a class from it with another member called B, the derived class will contain both member A and member B.

 

The inheritance relationship of two classes is declared in the derived class. Derived classes definitions use the following syntax:

 

class derived_class_name: public base_class_name

{ /*...*/ };

 

Where derived_class_name is the name of the derived class and base_class_name is the name of the class on which it is based. The public access specifier may be replaced by any one of the other access specifiers (protected or private). This access specifier limits the most accessible level for the members inherited from the base class: The members with a more accessible level are inherited with this level instead, while the members with an equal or more restrictive access level keep their restrictive level in the derived class.

 

// derived classes

#include<iostream>

usingnamespace std;

 

classPolygon {

  protected:

    intwidth, height;

  public:

    void set_values (int a, int b)

      { width=a; height=b;}

 };

 

classRectangle: publicPolygon {

  public:

    int area ()

      { returnwidth * height; }

 };

 

classTriangle: publicPolygon {

  public:

    int area ()

      { returnwidth * height / 2; }

  };

  

int main () {

  Rectangle rect;

  Triangle trgl;

  rect.set_values (4,5);

  trgl.set_values (4,5);

  cout << rect.area() << '\n';

  cout << trgl.area() << '\n';

  return 0;

}

 

you should get

 

20

10

 

 

The objects of the classes Rectangle and Triangle each contain members inherited from Polygon. These are: width, height and set_values.

 

The protected access specifier used in class Polygon is similar to private. Its only difference occurs in fact with inheritance: When a class inherits another one, the members of the derived class can access the protected members inherited from the base class, but not its private members.

 

By declaring width and height as protected instead of private, these members are also accessible from the derived classes Rectangle and Triangle, instead of just from members of Polygon. If they were public, they could be access just from anywhere.

 

We can summarize the different access types according to which functions can access them in the following way: 

 

Accesspublicprotectedprivate

members of the same classyesyesyes

members of derived classyesyesno

not membersyesnono

 

Where "not members" represents any access from outside the class, such as from main, from another class or from a function.

 

In the example above, the members inherited by Rectangle and Triangle have the same access permissions as they had in their base class Polygon:

 

Polygon::width           // protected access

Rectangle::width         // protected access

 

Polygon::set_values()    // public access

Rectangle::set_values()  // public access  

 

 

This is because the inheritance relation has been declared using the public keyword on each of the derived classes:

 

 

class Rectangle: public Polygon { /* ... */ }

 

 

This public keyword after the colon (:) denotes the most accessible level the members inherited from the class that follows it (in this case Polygon) will have from the derived class (in this case Rectangle). Since public is the most accessible level, by specifying this keyword the derived class will inherit all the members with the same levels they had in the base class.

 

With protected, all public members of the base class are inherited as protected in the derived class. Conversely, if the most restricting access level is specified (private), all the base class members are inherited as private and thus cannot be accessed from the derived class.

 

For example, if daughter were a class derived from mother that we defined as:

 

 

class Daughter: protected Mother;

 

 

This would set protected as the less restrictive access level for the members of Daughter that it inherited from mother. That is, all members that were public in Mother would become protected in Daughter. Of course, this would not restrict Daughter from declaring its own public members. That less restrictive access level is only set for the members inherited from Mother.

 

If no access level is specified for the inheritance, the compiler assumes private for classes declared with keyword class and public for those declared with struct.

 

What is inherited from the base class?

In principle, a derived class inherits every member of a base class except:

 

its constructors and its destructor

its assignment operator members (operator=)

its friends

 

Although the constructors and destructors of the base class are not inherited as constructors and destructors in the derived class, they are still called by the derived class's constructor. Unless otherwise specified, the constructors of derived classes call the default constructors of their base classes (i.e., the constructor taking no arguments), which must exist.

 

Calling a different constructor of a base class is possible, using the same syntax as to initialize member variables in the initialization list:

 

derived_constructor_name (parameters) : base_constructor_name (parameters) {...}

 

For example: 

 

// constructors and derived classes

#include<iostream>

usingnamespace std;

 

classMother {

  public:

    Mother ()

      { cout << "Mother: no parameters\n"; }

    Mother (int a)

      { cout << "Mother: int parameter\n"; }

};

 

classDaughter : publicMother {

  public:

    Daughter (int a)

      { cout << "Daughter: int parameter\n\n"; }

};

 

classSon : publicMother {

  public:

    Son (int a) : Mother (a)

      { cout << "Son: int parameter\n\n"; }

};

 

int main () {

  Daughter kelly(0);

  Son bud(0);

  

  return 0;

}

 

you should get

 

Mother: no parameters

Daughter: int parameter

 

Mother: int parameter

Son: int parameter

 

 

Notice the difference between which Mother's constructor is called when a new Daughter object is created and which when it is a Son object. The difference is due to the different constructor declarations of Daughter and Son:

 

1

2

Daughter (int a)          // nothing specified: call default constructor

Son (int a) : Mother (a)  // constructor specified: call this specific constructor 

 

 

Multiple inheritance

A class may inherit from more than one class by simply specifying more base classes, separated by commas, in the list of a class's base classes (i.e., after the colon). For example, if the program had a specific class to print on screen called Output, and we wanted our classes Rectangle and Triangle to also inherit its members in addition to those of Polygon we could write:

 

1

2

class Rectangle: public Polygon, public Output;

class Triangle: public Polygon, public Output; 

 

 

Here is the complete example: 

 

// multiple inheritance

#include<iostream>

usingnamespace std;

 

classPolygon {

  protected:

    intwidth, height;

  public:

    Polygon (int a, int b) : width(a), height(b) {}

};

 

classOutput {

  public:

    staticvoid print (int i);

};

 

void Output::print (int i) {

  cout << i << '\n';

}

 

classRectangle: publicPolygon, publicOutput {

  public:

    Rectangle (int a, int b) : Polygon(a,b) {}

    int area ()

      { returnwidth*height; }

};

 

classTriangle: publicPolygon, publicOutput {

  public:

    Triangle (int a, int b) : Polygon(a,b) {}

    int area ()

      { returnwidth*height/2; }

};

  

int main () {

  Rectangle rect (4,5);

  Triangle trgl (4,5);

  rect.print (rect.area());

  Triangle::print (trgl.area());

  return 0;

}

 

20

10  

(转) Friendship and inheritance的更多相关文章

  1. [C++] OOP - Access Control and Class Scope

    Access Control And Inheritance Protected Member Like private, protected members are unaccessible to ...

  2. 代码的坏味道(12)——平行继承体系(Parallel Inheritance Hierarchies)

    坏味道--平行继承体系(Parallel Inheritance Hierarchies) 平行继承体系(Parallel Inheritance Hierarchies) 其实是 霰弹式修改(Sho ...

  3. POJ 1815 Friendship

    Friendship Time Limit: 2000MS   Memory Limit: 20000K Total Submissions: 10626   Accepted: 2949 Descr ...

  4. 5.Inheritance Strategy(继承策略)【EFcode-first系列】

    我们已经在code-first 约定一文中,已经知道了Code-First为每一个具体的类,创建数据表. 但是你可以自己利用继承设计领域类,面向对象的技术包含“has a”和“is a”的关系即,有什 ...

  5. single-table inheritance 单表继承

    type 字段在 Rails 中默认使用来做 STI(single-table inheritance),当 type 作为普通字段来使用时,可以把SIT的列设置成别的列名(比如不存在的某个列). 文 ...

  6. C++: virtual inheritance and Cross Delegation

    Link1: Give an example Note: I think the Storable::Write method should also be pure virtual. http:// ...

  7. React之Composition Vs inheritance 组合Vs继承

    React的组合   composition: props有个特殊属性,children,组件可以通过props.children拿到所有包含在内的子元素, 当组件内有子元素时,组件属性上的child ...

  8. JavaScript Patterns 6.4 Prototypal Inheritance

    No classes involved; Objects inherit from other objects. Use an empty temporary constructor function ...

  9. JavaScript Patterns 6.2 Expected Outcome When Using Classical Inheritance

    // the parent constructor function Parent(name) { this.name = name || 'Adam'; } // adding functional ...

随机推荐

  1. C++中的函数指针用法

    代码: #include <iostream> #include <cstdio> typedef void (*FUN)(); using namespace std; vo ...

  2. c# 高效分页只需一个dll实例

    第一.首先下载WebUIControl.dll http://pan.baidu.com/s/1gdkilDh 第二.添加引用 三.应用实例-前台代码 <%@ Register Assembly ...

  3. 163k地方门户网站系统自动审核信息脚本

    本代码实现对163k地方门户网站系统发布信息的自动审核,以及对内容中链接全过滤 软件安装 Python 安装 http://www.python.org/download/ pymssql安装 htt ...

  4. keil c51编译器的一些使用心得

    现在的存储器已经不像七八年前那样昂贵了,但是ram相对于rom和eeprom的价格还是不可同样看待的,所以程序中节省内存在现在看来还是非常关键的.原因有以下几点: 1.ram的存取速度相对于eepro ...

  5. awk详解

    一.简介 强大的文本分析工具,基于指定规则浏览和抽取信息.简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理.awk有3个不同版本: awk.nawk和ga ...

  6. yum 配置详解(转发)

    一.yum 简介 yum,是Yellow dog Updater, Modified 的简称,是杜克大学为了提高RPM 软件包安装性而开发的一种软件包管理器.起初是由yellow dog 这一发行版的 ...

  7. 《Algorithms 4th Edition》读书笔记——2.4 优先队列(priority queue)-Ⅵ

    · 学后心得体会与部分习题实现 心得体会: 曾经只是了解了优先队列的基本性质,并会调用C++ STL库中的priority_queue以及 java.util.PriorityQueue<E&g ...

  8. 关于打开Eclipse时出现eclipse failed to create the java virtual machine与locking is not possible in the directory问题的解决

    今天在机子上使用Eclipse时候打开发现这两个问题,通过查阅资料膜拜大神博客得知解决方法,特此整理下来,方便后来遇到此问题的小伙伴们. 一开始打开Eclipse时候出现问题现象1,问题1解决以后就出 ...

  9. 格而知之16:我所理解的Block(2)

    11.那么Block到底是怎么实现的呢?试一试通过将Block 的代码转换成普通C语言代码来查看它的实现过程. 要将OC代码转换成C语言代码,可以使用clang编译的一个命令: 通过这个命令能把指定文 ...

  10. 简单的Dao设计模式

    简单的DAO设计模式 这两天学习到了DAO(Data Access Object 数据存取对象)设计模式.想谈谈自己的感受,刚开始接触是感觉有点难,觉得自己逻辑理不清,主要是以前学的知识比较零散没有很 ...