- 浏览: 99438 次
-
文章分类
最新评论
Friendship AND inheritance AND Polymorphism
Friendship and 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 affect
friends.
Friends are functions or classes declared with the friend
keyword.
If we want to declare an external function as friend of a class, thus allowing this function to have access to the private and protected members of this class, we do it by declaring a prototype of this external function within the class, and preceding it with
the keyword friend:
|
|
24 |
The duplicate function is a friend of CRectangle. From within that function we have been able to access the members
width and height of different objects of type CRectangle, which are private members. Notice that neither in the declaration of
duplicate() nor in its later use in main() have we considered
duplicate a member of class CRectangle. It isn't! It simply has access to its private and protected members without being a member.
The friend functions can serve, for example, to conduct operations between two different classes. Generally, the use of friend functions is out of an object-oriented programming methodology, so whenever possible it is better to use members of the same class
to perform operations with them. Such as in the previous example, it would have been shorter to integrate
duplicate() within the class CRectangle.
Friend classes
Just as we have the possibility to define a friend function, we can also define a class as friend of another one, granting that first class access to the protected and private members of the second one.
|
|
16 |
In this example, we have declared CRectangle as a friend of CSquare so that
CRectangle member functions could have access to the protected and private members of
CSquare, more concretely to CSquare::side, which describes the side width of the square.
You may also see something new at the beginning of the program: an empty declaration of class
CSquare. This is necessary because within the declaration of CRectangle we refer to CSquare (as a parameter in
convert()). The definition of CSquare is included later, so if we did not include a previous empty declaration for
CSquare this class would not be visible from within the definition of
CRectangle.
Consider that friendships are not corresponded if we do not explicitly specify so. In our example,
CRectangle is considered as a friend class by CSquare, but
CRectangle does not consider CSquare to be a friend, so CRectangle can access the protected and private members of
CSquare but not the reverse way. Of course, we could have declared also
CSquare as friend of CRectangle if we wanted to.
Another property of friendships is that they are not transitive: The friend of a friend is not considered to be a friend unless explicitly specified.
Inheritance between classes
A key feature of C++ classes is inheritance. Inheritance allows to create classes which are derived from other classes, so that they automatically include some of its "parent's" members, plus its own. For example, we are going to suppose that we want to
declare a series of classes that describe polygons like our CRectangle, or like
CTriangle. They have certain common properties, such as both can be described by means of only two sides: height and base.
This could be represented in the world of classes with a class CPolygon from which we would derive the two other ones:
CRectangle and CTriangle.
The class CPolygon would contain members that are common for both types of polygon. In our case:
width and height. And CRectangle and CTriangle 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 it to another class with another member called B, the derived class will contain both members
A and B.
In order to derive a class from another, we use a colon (:) in the declaration of the derived class using the following format:
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 and 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.
|
|
20 10 |
The objects of the classes CRectangle and CTriangle each contain members inherited from
CPolygon. These are: width, height and set_values().
The protected access specifier is similar to private. Its only difference occurs in fact with inheritance. When a class inherits from another one, the members of the derived class can access the protected members inherited from the base class,
but not its private members.
Since we wanted width and height to be accessible from members of the derived classes
CRectangle and CTriangle and not only by members of CPolygon, we have used
protected access instead of private.
We can summarize the different access types according to who can access them in the following way:
members of the same class | yes | yes | yes |
members of derived classes | yes | yes | no |
not members | yes | no | no |
Where "not members" represent any access from outside the class, such as from main(), from another class or from a function.
In our example, the members inherited by CRectangle and CTriangle have the same access permissions as they had in their base class CPolygon:
|
|
This is because we have used the public keyword to define the inheritance relationship on each of the derived classes:
|
|
This public keyword after the colon (:) denotes the most accessible level the members inherited from the class that follows it (in this case
CPolygon) will have. 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.
If we specify a more restrictive access level like protected, all public members of the base class are inherited as protected in the derived class. Whereas if we specify the most restricting of all access levels:
private, all the base class members are inherited as private.
For example, if daughter was a class derived from mother that we defined as:
|
|
This would set protected as the maximum 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 to declare its own public members. That maximum access level is only set for the members inherited from
mother.
If we do not explicitly specify any access level for the inheritance, the compiler assumes private for classes declared with
class keyword 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 constructor and its destructor
- its operator=() members
- its friends
Although the constructors and destructors of the base class are not inherited themselves, its default constructor (i.e., its constructor with no parameters) and its destructor are always called when a new object of a derived class is created or destroyed.
If the base class has no default constructor or you want that an overloaded constructor is called when a new derived object is created, you can specify it in each constructor definition of the derived class:
derived_constructor_name (parameters) : base_constructor_name (parameters) {...}
For example:
|
|
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 because the constructor declaration of
daughter and son:
|
|
Multiple inheritance
In C++ it is perfectly possible that a class inherits members from more than one class. This is done by simply separating the different base classes with commas in the derived class declaration. For example, if we had a specific class to print on screen
(COutput) and we wanted our classes CRectangle and CTriangle to also inherit its members in addition to those of
CPolygon we could write:
|
|
here is the complete example:
|
|
20 10 |
Polymorphism
Before getting into this section, it is recommended that you have a proper understanding of pointers and class inheritance. If any of the following statements seem strange to you, you should review the indicated sections:
int a::b(int c) { } | Classes |
a->b | Data Structures |
class a: public b { }; | Friendship and inheritance |
Pointers to base class
One of the key features of derived classes is that a pointer to a derived class is type-compatible with a pointer to its base class. Polymorphism is the art of taking advantage of this simple but powerful and versatile feature, that brings Object Oriented
Methodologies to its full potential.
We are going to start by rewriting our program about the rectangle and the triangle of the previous section taking into consideration this pointer compatibility property:
|
|
20 10 |
In function main, we create two pointers that point to objects of class
CPolygon (ppoly1 and ppoly2). Then we assign references to
rect and trgl to these pointers, and because both are objects of classes derived from
CPolygon, both are valid assignment operations.
The only limitation in using *ppoly1 and *ppoly2 instead of
rect and trgl is that both *ppoly1 and *ppoly2 are of type
CPolygon* and therefore we can only use these pointers to refer to the members that
CRectangle and CTriangle inherit from CPolygon. For that reason when we call the
area() members at the end of the program we have had to use directly the objects
rect and trgl instead of the pointers *ppoly1 and
*ppoly2.
In order to use area() with the pointers to class CPolygon, this member should also have been declared in the class
CPolygon, and not only in its derived classes, but the problem is that
CRectangle and CTriangle implement different versions of area, therefore we cannot implement it in the base class. This is when virtual members become handy:
Virtual members
A member of a class that can be redefined in its derived classes is known as a virtual member. In order to declare a member of a class as virtual, we must precede its declaration with the keyword
virtual:
|
|
20 10 0 |
Now the three classes (CPolygon, CRectangle and CTriangle) have all the same members:
width, height, set_values() and area().
The member function area() has been declared as virtual in the base class because it is later redefined in each derived class. You can verify if you want that if you remove this
virtual keyword from the declaration of area() within CPolygon, and then you run the program the result will be
0 for the three polygons instead of 20, 10 and 0. That is because instead of calling the corresponding
area() function for each object (CRectangle::area(), CTriangle::area() and
CPolygon::area(), respectively), CPolygon::area() will be called in all cases since the calls are via a pointer whose type is
CPolygon*.
Therefore, what the virtual keyword does is to allow a member of a derived class with the same name as one in the base class to be appropriately called from a pointer, and more precisely when the type of the pointer is a pointer to the base class but
is pointing to an object of the derived class, as in the above example.
A class that declares or inherits a virtual function is called a polymorphic class.
Note that despite of its virtuality, we have also been able to declare an object of type
CPolygon and to call its own area() function, which always returns 0.
Abstract base classes
Abstract base classes are something very similar to our CPolygon class of our previous example. The only difference is that in our previous example we have defined a valid
area() function with a minimal functionality for objects that were of class
CPolygon (like the object poly), whereas in an abstract base classes we could leave that
area() member function without implementation at all. This is done by appending
=0 (equal to zero) to the function declaration.
An abstract base CPolygon class could look like this:
|
|
Notice how we appended =0 to virtual int area () instead of specifying an implementation for the function. This type of function is called a
pure virtual function, and all classes that contain at least one pure virtual function are
abstract base classes.
The main difference between an abstract base class and a regular polymorphic class is that because in abstract base classes at least one of its members lacks implementation we cannot create instances (objects) of it.
But a class that cannot instantiate objects is not totally useless. We can create pointers to it and take advantage of all its polymorphic abilities. Therefore a declaration like:
|
|
would not be valid for the abstract base class we have just declared, because tries to instantiate an object. Nevertheless, the following pointers:
|
|
would be perfectly valid.
This is so for as long as CPolygon includes a pure virtual function and therefore it's an abstract base class. However, pointers to this abstract base class can be used to point to objects of derived classes.
Here you have the complete example:
|
|
20 10 |
If you review the program you will notice that we refer to objects of different but related classes using a unique type of pointer (CPolygon*). This can be tremendously useful. For example, now we can create a function member of the abstract base class
CPolygon that is able to print on screen the result of the area() function even though
CPolygon itself has no implementation for this function:
|
|
20 10 |
Virtual members and abstract classes grant C++ the polymorphic characteristics that make object-oriented programming such a useful instrument in big projects. Of course, we have seen very simple uses of these features, but these features can be applied to arrays
of objects or dynamically allocated objects.
Let's end with the same example again, but this time with objects that are dynamically allocated:
|
|
20 10 |
Notice that the ppoly pointers:
|
|
are declared being of type pointer to CPolygon but the objects dynamically allocated have been declared having the derived class type directly.
相关推荐
this is an example for polymorphism and inheritance feature of OOP C++. A reference for C++ starter.
### 可移植的继承与多态在C语言中的实现 #### 概述 本文探讨了在非面向对象语言如C中实现面向对象编程的可能性。它解答了如何在没有C++编译器的小型嵌入式系统中实现面向对象设计、如何改进C语言编码风格使其更加...
在`java_inheritance_and_polymorphism-master`这个项目中,可能包含了关于这些概念的实际代码示例和练习,你可以通过阅读和实践这些代码来深入理解Java中的继承和多态性。通过这些练习,你可以学习如何设计和使用...
Objected_oriented programming is a practical and useful programming methodology that encourage moduler design and software reuse.Most Objected_oriented programming language support data abstraction by...
在探讨《渠化的发展与后天性状的遗传》这一主题时,我们首先需要了解文章的核心概念及其背景。本文由沃丁顿(Waddington)于1942年发表在《自然》杂志上,主要关注了两个核心议题:发展生物学中的“渠化”现象以及...
Data Structures and Other Objects Using C++ takes a gentle approach to the data structures course in C++....Chapter 14 Derived Classes and Inheritance Derived Classes and Inheritance Chapter 15 Graphs
Chapter 6: Understanding Inheritance and Polymorphism Chapter 7: Understanding Structured Exception Handling Chapter 8: Working with Interfaces Part IV: Advanced C# Programming Chapter 9: Collections...
How do you choose between inheritance and templates? Between templates and generic pointers? Between public and private inheritance? Between private inheritance and layering? Between function ...
在Java编程语言中,封装、继承和多态是面向对象编程的三大核心概念,它们为构建复杂的软件系统提供了坚实的基础。下面将详细讲解这些概念及其重要性。 **封装**是面向对象编程的基本原则之一,它涉及到将数据和操作...
#Java中的多态性和继承###是什么? 一个Java项目,以演示和理解Java中的多态性和继承。 该项目使用Java 7。 ###如何使用? 这是一个eclipse项目,因此要从eclipse中执行以下步骤以导入该项目: eclipse > file > ...
Key concepts read like a list of Java features: Object oriented design, variable type and scope, object properties and methods, inheritance and polymorphism, exceptions, graphical user interfaces ...
Key concepts read like a list of Java features: Object oriented design, variable type and scope, object properties and methods, inheritance and polymorphism, exceptions, graphical user interfaces ...
Simplifies object-oriented concepts, including classes, interfaces, polymorphism, and inheritance Contains detailed chapters on exceptions and logging, math, I/O, reflection, multithreading, and ...
Topics include object-oriented programming (OOP) concepts, such as inheritance and polymorphism, and how they can be leveraged in C++ to create more robust and maintainable software. The chapter also...
Chapter 6: Understanding Inheritance and Polymorphism Chapter 7: Understanding Structured Exception Handling Chapter 8: Working with Interfaces Part IV: Advanced C# Programming Chapter 9: Collections...
Part V: Inheritance and Polymorphism HOUR 16: Extending Classes with Inheritance HOUR 17: Using Polymorphism and Derived Classes HOUR 18: Making Use of Advanced Polymorphism Part VI: Special Topics ...