How operator overloading works in C++

operator overloading c++ implementation and operator overloading c++ video tutorial and operator overloading c++ list operator overloading c++ complex numbers
Dr.NaveenBansal Profile Pic
Dr.NaveenBansal,India,Teacher
Published Date:25-10-2017
Your Website URL(Optional)
Comment
CHAPTER 4 Classes and Abstract Data Types This chapter introduces the reader to classes. The original name given by Bjarne Stroustrup to his language was “C with classes.” The name C++ was coined by Rick Mas- citti in 1983, being a pun on the ++ increment operator. Stroustrup had extensive expe- rience with Simula67, the first object-oriented language. It was developed in 1967 to be a simulation language and added the construct class to its base language, ALGOL60. A class in C++ is an extension of the idea of struct found in C. A class packages a data type with its associated functions and operators. This in turn can be used to implement abstract data types (ADTs). An abstract data type, such as a stack, is a set of values and operations that define the type. The type is abstract in that it is described without its implementation. It is the job of the C++ programmer to provide a concrete representa- tion of the ADT. This is usually done with the class. C++ classes bundle data declarations with function declarations, thereby coupling data with behavior. The class description also has access modifiers public and private that allow data hiding. Allowing private and public visibility for members gives the pro- grammer control over what parts of the data structure are modifiable. The private parts are hidden from client code, and the public parts are available. It is possible to change the hidden representation, but not to change the public access or functionality. If this is done properly, client code need not change when the hidden representation is modi- fied. A large part of the object-oriented programming (OOP) design process involves thinking up the appropriate ADTs for a problem. Good ADTs not only model key fea- tures of the problem but also are frequently reusable in other code.Ira Pohl’s C++ by Dissection 4.1 The Aggregate Type class and struct 140 4.1 4.1 The Aggregate Type class and struct The class or struct type allows the programmer to aggregate components into a sin- gle named variable. A class has components, called members, that are individually named. Since the members of a structure can be of various types, the programmer can create aggregates that are suitable for describing complicated data. Student Cards Stack As a simple example, let us define a structure that describes a point. We can declare the structure type as follows: struct point double x, y; ; In C++, the structure name, or tag name, is a type. In the preceding declaration, struct is a keyword, point is the structure tag name, and the variables x and y are members of the structure. The declaration point can be thought of as a blueprint; it creates the type point, but no instances are allocated. The declaration point pt; allocates storage for the variable pt. To access the members of pt, we use the member access operator, represented by a period, or dot. It is a construct of the form structure_variable.member_name The construct is used as a variable in the same way that a simple variable or an element of an array is used. Suppose that we want to assign to pt the value (–1, +0.5). To do this, we can write pt.x = -1; pt.y = 0.5; The member name must be unique within the specified structure. Since the member must always be prefaced or accessed through a unique structure variable identifier,Ira Pohl’s C++ by Dissection 4.2 Member Selection Operator 141 there is no confusion between two members that have the same name in different struc- tures, as in struct fruit char name15; int calories; ; struct vegetable char name15; int calories; ; fruit a; // struct fruit a; in C vegetable b; // struct vegetable b; in C Having made these declarations, we can access a.calories and b.calories without ambiguity. In general, a structure is declared with the keyword struct, followed by an identifier (tag name), followed by a brace-enclosed list of member declarations, followed by a semicolon. The tag name is optional but should be expressive of the ADT concept being modeled. When there is no tag name, the structure declaration is anonymous and can be used only to declare variables of that type immediately: struct int a, b, c; triples 2 = 3, 3, 6, 4, 5, 5 ; Note: Omitting the semicolon at the end of a declaration is a typical syntax error. We use two-dimensional point example in much of this chapter. You should see at dif- ferent places in the text whether you can extend these ideas to a three-dimensional point. To test your understanding, do exercise 2 on page 179. 4.2 4.2 Member Selection Operator Now we introduce the member selection operator -, which provides access to the members of a structure via a pointer. This operator is typed on the keyboard as a minus sign followed by a greater-than sign. If a pointer variable is assigned the address of a structure, a member of the structure can be accessed by a construct of the form pointer_to_structure - member_name An equivalent construct is given by (pointer_to_structure).member_nameIra Pohl’s C++ by Dissection 4.2 Member Selection Operator 142 The operators - and ., along with () and , have the highest precedence, and they associate left to right. In complicated situations, the two accessing modes can be com- bined. Here is the point structure: struct point double x, y; ; Table 4.1 illustrates its use: Table 4.1 Declarations and Initialization point w, p = &w; point v5; w.x = 1; w.y = 4; v0 = w; Expression Equivalent Expression Value w.x p-x 1 w.y p - y 4 v0.x v-x 1 (p).y p - y 4 The member w.x was assigned 1. Therefore, the equivalent expression “pointer p accessing member x” is 1. The assignment v0 = w assigns values member by mem- ber. Therefore, v0.x is 1. A more complete example using point is the following: In file struct_point1.cpp // Compute an average point struct point double x, y; ; point average(const point d, int size) point sum = 0, 0; for (int i = 0; i size; i++) sum.x += d-x; sum.y += d-y; d++; // d is iterator accessing each point sum.x = sum.x / size; sum.y = sum.y / size; return sum; Ira Pohl’s C++ by Dissection 4.3 Member Functions 143 int main() point data5 = 1.0, 2.0, 1.0, 3.3, 5.1, 0.5, 2.0, 2.0, 0, 0 ; point average_point; average_point = average(data, 5); cout "average point = (" average_point.x ", " average_point.y ") " endl; 4.3 4.3 Member Functions C++ allows functions to be members. C allows only data members. The function decla- ration is included in the structure declaration. The idea is that the functionality required by the structure or class should often be directly included in the class or struct declaration. Such functions are called class methods. This term method, mean- ing member function, comes from object-oriented programming methodology. This con- struct improves the encapsulation of the ADT point operations by packaging it directly with its data representation. An informal idea for designing an object is to think of the object as a noun, such as point, and to think of methods as verbs that apply to the noun, such as print(). Let us add a printing operation and an initializing operation to the ADT point: In file point1.cpp struct point double x, y; void print() const cout "(" x "," y ")"; void set(double u, double v) x = u; y = v; ; The member functions, or methods, are written in much the same way that other func- tions are. One difference is that they can use the data member names directly. Thus, the member functions in point use x and y in an unqualified manner. When invoked on a particular object of type point, they act on the specified member in that object. Let us use these member functions in an example:Ira Pohl’s C++ by Dissection 4.3 Member Functions 144 int main() point w1, w2; w1.set(0, 0.5); w2.set(-0.5, 1.5); cout "\npoint w1 = "; w1.print(); cout "\npoint w2 = "; w2.print(); cout endl; This prints point w1 = (0,0.5) point w2 = (-0.5,1.5) Dissection of the point Structure struct point double x, y; In classical programming, structures are user-defined data types that bundle previously defined data types into a new type. In this case, the new type is point. Its constituents are two doubles, the coordinates represented by variables x and y. void print() const cout "(" x "," y ")"; void set(double u, double v) x = u; y = v; Object-oriented programming requires that functions be bundled with data and become the actions available to the type. These mem- ber functions are also called methods. Here is a simple print() method that prints out a value for a point. The set() method is used to change the values of the point’s coordinates. As we shall see in further examples, it is part of the object-oriented programming style to use member functions to access the data representation of an object type. It is considered poor programming practice to directly manipulate these values in an unrestrained fashion. The const modi- fier after the function declaration indicates that the function will not modify any class members. (See Section 4.10, const Members, on page 161.)Ira Pohl’s C++ by Dissection 4.3 Member Functions 145 int main() point w1, w2; The newly defined type looks like any of the native types. Here, two points are declared in main(). w1.set(0, 0.5); w2.set(-0.5, 1.5); cout "\npoint w1 = "; w1.print(); Notationally, to call methods of type point requires a point variable dotted to the method name. In the first line, the point w1 is set to the coordinates (0, 0.5). In the last line, these coordinates would be printed out by the method print(). Member functions that are defined within the struct are implicitly inline. As a rule, only short, heavily used member functions should be defined within the struct, as in the example just given. To define a member function outside the struct, the scope res- olution operator is used (see Section 4.6, Class Scope, on page 150). Let us illustrate this by adding a member function, point::plus(). We write it out fully, using the scope resolution operator. In this case, the function is not implicitly inline. In file point1.cpp struct point ····· void plus(point c); // function prototype ····· ; // offset the existing point by point c void point::plus(point c) // definition not inline x += c.x; y += c.y; Member functions within the same struct can be overloaded. Consider adding to the data type point a print operation that has a string parameter printed as the name of the point. The print operation could be added as the following function prototype within the struct.Ira Pohl’s C++ by Dissection 4.4 Access: Private and Public 146 In file point1.cpp struct point ····· void print(const string& name) const; ····· ; void point::print(const string& name) const cout name " (" x "," y ")"; The definition that is invoked depends on the arguments to print(): w1.print(); // standard print w1.print("\npoint w1 = "); // print with name A member function is conceptually part of the type. The inline specification can be used explicitly, with member functions defined at file scope, which avoids having to clutter the class definition with function bodies. The grouping of operations with data emphasizes their objectness. Objects have a description and a behavior. Thinking of an object as a noun and its behavior as the verbs that are most often associated with that noun is key to good object design. OOP is a data-centered design approach. 4.4 4.4 Access: Private and Public In C++, structures have public and private members. The keyword private followed by a colon is used to declare subsequent members to have private access. The private members can be used by only a few categories of functions. Class member functions can use private members, and friend functions of the class can use private members. Friend functions are discussed in Section 5.10, Friend Functions, on page 211. The keyword public followed by a colon is used to declare subsequent members to have public access. The public members can be used by any code. We modify our example of point to hide its data representation, as follows: In file point2.cpp struct point public: void print() const cout "(" x "," y ")"; void print(const string& name) const; void set(double u, double v) x = u; y = v; void plus(point c); private: double x, y; ;Ira Pohl’s C++ by Dissection 4.5 Classes 147 In the following code, an attempt by a nonmember function, foo(), to access the now private members x and y results in a syntax error: void foo(point w) ····· cout " x coordinate = " w.x; // syntax error ····· The keyword protected followed by a colon is used to declare subsequent members to have protected access. The protected members can be thought of as private members but with special rules when they are used by a derived class. This is not used here but is explained in Section 8.1, A Derived Class, on page 330. Hiding data is an important component of OOP. It allows for more easily debugged and maintained code because errors and modifications are localized. Client programs need be aware only of the type’s interface specification. This is also known as the black box principle. A good design hides unnecessary implementation detail and presents the sim- plest possible useful user interface to the client. The interface is great, but what does it do? 4.5 4.5 Classes Classes in C++ are introduced by the keyword class. A form of struct, classes have a default privacy specification of private, in contrast to structures defined with struct, which have a default privacy specification of public. Thus, struct and class can be used interchangeably with the appropriate access specifications. In the following exam- ple, we modify point to use class:Ira Pohl’s C++ by Dissection 4.5 Classes 148 In file point3.cpp class point double x, y; // implicitly private public: void print() const cout "(" x "," y ")"; void print(const string& name) const; void set(double u, double v) x = u; y = v; void plus(point c); ; Contemporary C++ style is to use access specifiers explicitly rather than rely on defaults. The use of implicit features is labor-saving but error-prone. Therefore, it is better style to declare point as follows: In file point4.cpp class point public: // place public members first void print() const cout "(" x "," y ")"; void print(const string& name) const; void set(double u, double v) x = u; y = v; void plus(point c); private: double x, y; ; When access keywords are used, struct and class are interchangeable. Stylistically, professional C++ programmers use class in preference to struct unless the struct has only public data members. This text uses access keywords explicitly and places public members first and private members last. In this need-to-know style, everyone needs to know the public interface, but only the class provider needs to know the pri- vate implementation details. At this point, you should at this point be able to write a class pair. The class pair, like point, has two fundamental values; for example, the first value might be a name and the second value a telephone number. Such a pair could provide you an online way of keeping your personal phone list. You must show your membership card to get in I’m sorry, sir, but I really cannot let you have accessunless you are a member.Ira Pohl’s C++ by Dissection 4.5 Classes 149 As a second example, let us write an ADT for customer, which many business applica- tions require. As part of this representation, we will use the Standard Template Library (STL) string type. This type overloads the binary operator + to produce string concate- nation. In file customer.cpp enum c_kind general, wholesale, retail ; class customer public: void set_name(const string& l, const string& f) last_name = l; first_name = f; c_kind get_kind() const return t; void set_kind(c_kind k) t = k; void print() const cout (first_name + " " + last_name) endl; double price_discount() const; private: string last_name, first_name; int id_number; c_kind t; ; double customer::price_discount() const if (t == wholesale) return 0.20; else return 0.1; The class customer is an ADT in which the enum type c_kind distinguishes among three categories of customer so that a different pricing structure can be applied for each category. Let us write a main() that tests the use of this new type: int main() customer c, d; c.set_name("Pohl", "Ira"); c.set_kind(wholesale); c.print(); cout "\nYour PC costs " 900 (1 - c.price_discount()) " dollars." endl; Ira Pohl’s C++ by Dissection 4.6 Class Scope 150 Here is the output from this test program: Ira Pohl Your PC costs 720 dollars. Dissection of the customer Class enum c_kind general, wholesale, retail ; Simple ADTs are expressible as an enum type. The enumeration can be declared inside or outside the class. private: string last_name, first_name; int id_number; c_kind t; ; Implementation is almost always hidden in accord with the black box principle. c_kind get_kind() const return t; void set_kind(c_kind k) t = k; These are typical member functions. There is usually a set() and a get() method for each data member of the internal representation. This is part of the public interface for the ADT. It allows, in a con- trolled fashion, access to key values for the customer type. 4.6 4.6 Class Scope Classes add new scope rules to those of the kernel language. Classes provide an encap- sulation technique. Conceptually, it makes sense that all names declared within a class be treated within their own scope, as distinct from external names, namespace names, function names, and other class names, creating a need for a scope resolution operator. 4.6.1 Scope Resolution Operator The scope resolution operator, the highest-precedence operator in the language, comes in two forms. The unary form is used to uncover or to access a name that has external scope and has been hidden by local or class scope. The binary form places the class or namespace identifier before the operator and the identifier after the operator.Ira Pohl’s C++ by Dissection 4.6 Class Scope 151 ::i // unary - refers to external scope point::x // binary - refers to class scope std::cout // binary - refers to namespace scope In file how_many1.cpp int count = 0; // global count void how_many(double w, double x, int& count) for (int i = 0; i N; ++i) count += (wi == x); // local count ++::count; // global count tracks calls To understand this program fragment, change the parameter int& count to int& cnt. Now there is no need for the scope resolution operator, as the two identifiers are dis- tinct. In file how_many2.cpp int count = 0; // global count void how_many(double w, double x, int& cnt) for (int i = 0; i N; ++i) cnt += (wi == x); ++count; // global count tracks calls Binary scope resolution is used to clarify names that are reused within classes. class widgets public: void f(); ; class gizmos public: void f(); ; void f() ····· // ordinary external f void widgets::f() ····· // f scoped to widgets void gizmos::f() ····· // f scoped to gizmos One way to think about the scope resolution operator is to view it as providing a path to the identifier. If there is no scope modifier, normal scope rules apply. Continuing with the previous example: widgets w; gizmos g; g.f(); w.f(); g.gizmos::f(); // legal but redundant g.widgets::f(); // illegal-widgets can’t act on gizmoIra Pohl’s C++ by Dissection 4.6 Class Scope 152 4.6.2 Nested Classes Like blocks and namespaces, classes are scopes and can nest. Nesting allows local hid- ing of names and local allocation of resources. This is often desirable when a class is needed as part of the implementation of a larger construct. The following nested classes illustrate current C++ rules: In file nested.cpp char c; // external scope ::c class X // outer class declaration X:: public: char c; // X::c class Y // inner class declaration X::Y:: public: void foo(char e) X t; ::c = t.c = c = e; private: char c; // X::Y::c ; ; In class Y, the member function foo(), when using ::c, references the global variable c; when using X::c, it references the outer class variable; when using c, it references the inner class variable X::Y::c. All three variables named c are accessible using the scope resolution operator. Furthermore, purely locally scoped classes can be created within blocks. Their definitions are unavailable outside their local block context. void foo() class local ····· x; local y; // illegal:local is scoped within foo() Notice that C++ allows you to nest function definitions by using class nesting, which is a restricted form of function nesting. The member functions must be defined inside the local class and cannot be referred to outside this scope. So which nest is mine?Ira Pohl’s C++ by Dissection 4.7 An Example: Flushing 153 Avoid unnecessary nesting as it creates hard-to-follow, complex designs. Good choice of distinct names is preferable to distinguishing identifiers by scope. 4.7 4.7 An Example: Flushing We want to estimate the probability of being dealt a flush in poker. A flush occurs when at least five cards are of the same suit. We simulate shuffling cards by using a random number generator. This is a form of Monte Carlo calculation, named after the famous gambling resort. As was already mentioned in Section 3.20, Problem Solving: Random Numbers, on page 108, a Monte Carlo calculation is a computer simulation program requiring a probability calculation. The program uses classes to represent the necessary data types and functionality. The key data type is card, which consists of a suit value and a pips value. A pips value is between 1 and 13. On an actual card, these 13 pips values are ace, 2, 3, ·····, 10, jack, queen, and king. In file poker.cpp enum suit clubs, diamonds, hearts, spades ; class pips public: void set_pips(int n) p = n % 13 + 1; int get_pips() const return p; void pr_pips() const cout p; private: int p; // meant to hold values 1,13 ; class card public: void set_card(int n) s = static_castsuit(n/13); p.set_pips(n); void pr_card() const; suit get_suit() const return s; pips get_pips() const return p; private: suit s; pips p; ;Ira Pohl’s C++ by Dissection 4.7 An Example: Flushing 154 class deck public: void set_deck(); void shuffle(); void deal(int, int, card); void pr_deck() const; private: card d52; ; void deck::set_deck() for (int i = 0; i 52; ++i) di.set_card(i); void deck::shuffle() for (int i = 0; i 52; ++i) int k = i + (rand() % (52 - i)); card t = di; // swap cards di = dk; dk = t; void deck::deal(int n, int pos, card hand) for (int i = pos; i pos + n; ++i) handi - pos = di; Dissection of the deck Class enum suit clubs, diamonds, hearts, spades ; class pips public: void set_pips(int n) p = n % 13 + 1; ····· private: int p; // meant to hold values 1,13 ; The class pips and the enum suit are used to build the card type. The set_pips() method uses integers 0 to 51 to set an appropriate pips value for a card. The clustering of member functions and the data members they act on improves modularity. Behavior and description are logically grouped together. Ira Pohl’s C++ by Dissection 4.7 An Example: Flushing 155 class card public: void set_card(int n) s=static_castsuit(n/13); p.set_pips(n); ····· private: suit s; pips p; ; Each level of declaration hides the complexity of the previous level. The class card uses suit and pips in its representation. The set_card() method uses integer division to generate an enumerator value. To recode suit as a class type, you could have a set_suit() method do the same computation. class deck public: void set_deck(); void shuffle(); void deal(int, int, card); void pr_deck() const; private: card d52; ; The class deck declares only the class member functions; defini- tions come later. void deck::set_deck() for (int i = 0; i 52; ++i) di.set_card(i); The set_deck() function calls card::set_card() to map the inte- gers into card values. Again we notice how each part of the design enables us to segregate function and description into appropriate object types.Ira Pohl’s C++ by Dissection 4.7 An Example: Flushing 156 void deck::shuffle() for (int i = 0; i 52; ++i) int k = i + (rand() % (52 - i)); card t = di; // swap cards di = dk; dk = t; The shuffle() function uses the library-supplied pseudo-random number generator rand() in stdlib to exchange two cards for every deck position. We now write main() to test these classes by computing the odds of getting a dealt-out flush in a poker game. We allow the user to decide how many cards to play, as there are many poker variants that require between five and nine cards per hand. include iostream include ctime // needed for time() include cstdlib // needed for rand() and srand() using namespace std; int main() card one_hand9; // max hand is 9 cards deck dk; int i, j, k, flush_count = 0, sval4; int ndeal, nc, nhand; do cout "\nEnter no. cards in a hand (5-9): "; cin nc; while (nc 5 nc 9); nhand = 52 / nc; cout "Enter no. of hands to deal: "; cin ndeal; srand(time(NULL)); // seed rand() from time() dk.set_deck(); for (k = 0; k ndeal; k += nhand) if ((nhand + k) ndeal) nhand = ndeal - k; dk.shuffle(); for (i = 0; i nc nhand; i += nc) for (j = 0; j 4; ++j) // zero suit counts svalj = 0; dk.deal(nc, i, one_hand); // deal next hand for (j = 0; j nc; ++j) svalone_handj.get_suit()++; // +1 to suitIra Pohl’s C++ by Dissection 4.7 An Example: Flushing 157 for (j = 0; j 4; ++j) if (svalj = 5) // 5 or more is flush flush_count++; cout "\nIn " ndeal " "; cout nc "-card hands there were "; cout flush_count " flushes\n"; Dissection of the poker Program do cout "\nEnter no. cards in a hand (5-9): "; cin nc; while (nc 5 nc 9); nhand = 52 / nc; cout "Enter no. of hands to deal: "; cin ndeal; We first ask the user to enter a number of cards per hand. We insist with a do loop that we get an integer between 5 and 9. We then input the number of hands to run the computation on. For a relatively rare hand, such as a flush, we need a high number of hands to get a rea- sonable estimate of the probability of flushing. Notice we did not insist on checking that the number of hands dealt was between some integer values. A more robust program might also use a do loop for this input as well. srand(time(NULL)); // seed rand() from time() dk.set_deck(); for (k = 0; k ndeal; k += nhand) if ((nhand + k) ndeal) nhand = ndeal - k; dk.shuffle(); The deck is initialized and then shuffled using the random number generator. Each time the deck is dealt, the number nhand represents how many poker hands per shuffle can be arranged. If we were deal- ing six-card hands, this would be 8, as 68 is 48, but 78 is 56 (too many cards for a 52-card deck). Also note that the library ctime needs to be included for the call to time(). for (j = 0; j nc; ++j) svalone_handj.get_suit()++; // +1 to suit For each card, we get its suit value. The suit value is an enumerator that can be used as an index into the sval array. Each of the four ele- ments of sval stores how many of each suit is found in a given hand. If one of these values is at least 5, the hand is a flush.Ira Pohl’s C++ by Dissection 4.8 The this Pointer 158 You can test your understanding of the poker program by modifying it to compute the probability of other poker hands. It is straightforward to compute whether a hand has a straight. A straight is a hand that has five cards whose pips value are in sequence, such as having a (3, 4, 5, 6, 7). A Bold Bluff One of a series of Dogs Playing Poker by C. M. Coolidge 4.8 4.8 The this Pointer The keyword this denotes an implicitly declared self-referential pointer that can be used in a nonstatic member function. Later, we discuss static member functions, where the this pointer is not available. A simple illustration of the pointer’s use follows. In file point5.cpp // Class illustrating the use of the this pointer class point public: // place public members first void print() const cout "(" x "," y ")"; void print(const string& name) const; void set(double u, double v) x = u; y = v; void plus(point c); point inverse() x = -x; y = -y; return (this); point where_am_I() return this; private: double x, y; ; // Offset the existing point by point c void point::plus(point c) x += c.x; y += c.y;

Advise: Why You Wasting Money in Costly SEO Tools, Use World's Best Free SEO Tool Ubersuggest.