answersLogoWhite

0


Best Answer

All operators can be overloaded with the exception of the sizeof, typeid, member-of (.), pointer to member (.*), ternary conditional (?:) and scope resolution (::) operators.

Operators may be unary (those that accept one operand) or binary (those that accept two operands). The ternary conditional operator is the only operator that accepts three operands but it cannot be overloaded.

Before overloading an operator, you must first consider the types of its operand(s) and also the type of its return value. All operators must return something, whether it is the logical NOT of an object (a unary operation) or the sum of two objects (a binary operation). However it's easy to get carried away with overloads in order to cater for every possible combination of types, and this can quickly lead to code duplication, inconsistencies and code that is much harder to maintain.

Ideally, all operators should be implemented as free functions (global functions). In so doing you gain the advantage of implicit conversion between types, thus reducing the number of overloads required for any given operation. The only operator overloads that must be implemented as member functions are the copy and move assignment operators, so let's begin with those.

Let's consider a class that encapsulates a year. We'll assume negative years denote BC and positive years denote AD, thus we'll use a signed integral as our representation. However, there was no year zero (we went from 1BC to 1AD), thus our class has an invariant -- it must not be zero.

class year

{

private:

int64_t m_data; // 64-bit signed integral

public:

year (int64_t y): m_data {y} { if (!y) throw std::range_error ("Error: no year zero!"); }

year (const year& y): m_data {y.m_data} {}

year (year&& y): m_data {std::move (y.m_data)} {}

year& operator= (const year& y) {m_data = y.m_data; }

year& operator= (year&& y) { m_data = std::move (y.m_data); }

~year () {}

};

Our class has one conversion constructor which allows us to implicitly convert from any 64-bit integer to a year. However, since the language has built-in conversions for all integrals we can implicitly construct a year from any integral, including a char, an int, a long, a short and so on. The only integral type we cannot implicitly convert is an unsigned 64-bit integral since this could exceed the bounds of our signed integral by up to an order of two. However, the compiler should warn us about this "narrowing" and helps us keep the class as simple as possible.

Note that the conversion constructor is the only constructor that maintains the invariant (non-zero years). Since the copy and move constructors can only work with pre-existing instances of our year class, those instances would not exist unless they had originally been constructed through conversion.

The copy and move assignment operators also cater for pre-existing instances of our year class, but we can also assign from any signed integral because we provided a conversion constructor to cater for this. This makes it possible to perform the following:

year y {2014};

y = -1;

The first statement initialises a year with the literal integral 2014. That is, the value 2014 is implicitly converted to an int64_t (which is what the conversion constructor expects), and the constructor instantiates a year object with that value. The second statement replaces that value with the literal integral -1 even though we did not provide an assignment operator overload to cater for this. Behind the Scenes, the compiler constructs a temporary year object from the literal (just as it did with 2014), and then uses that temporary object to perform the actual assignment. The temporary object falls from scope at the end of the statement.

The stream insertion and extraction operators often cause problems for new programmers in the mistaken belief that all operators related to a class should be members of that class just as the copy and move assignment operators must be. However, this is not the case; all other operator overloads should ideally be non-member functions whenever possible, especially when the return value is of a different type. In this case the return value is a reference to the stream being operated upon. We cannot provide these overloads as members of the stream nor as members of the type, therefore we have no option but to define them as free functions:

std::ostream& operator<< (std::ostream& os, const year& y)

{

return os << y.m_data;

}

The problem with this is that year::m_data is private. We could provide a public accessor (in many cases this would be the preferred option), but we must also never expose an interface without good reason. If this were the only function that actually required that accessor then it would not make sense to provide one. A public accessor is intended to be used by anyone and everyone. In this case we could simply return the member by value (and thus maintain encapsulation of the invariant), but in a more complex object we may not wish to expose the entire representation in this way because returning by value can be expensive in terms of both performance and memory. Returning by constant reference is another option but, again, this could expose far more than we wish to expose, which ultimately undermines the encapsulation. The best solution is simply to declare those functions that require private access as friends of the class:

class year

{

// ...

friend std::ostream& operator<< (std::ostream&, const year&);

};

Note that a friend is not a member of the class that declares it a friend, nor does it undermine encapsulation (if anything, it enforces it). The best way to think of it is to examine the three logically distinct things that every ordinary member function declaration specifies:

1. The function has private access to the class representation.

2. The function is in the scope of the class.

3. The function must be invoked upon an instance of the class (has a 'this' pointer).

A static member function declares the first two while a friend only declares the first. It therefore follows that if you believe a friend undermines encapsulation, then you must also believe every member function also undermines encapsulation -- and to a much greater degree. But you are the author of your own class' encapsulation rules; it's entirely up to you how you implement them, whether those implementations are within your own class member functions, your own static member functions or your own friends of the class.

Although friends are not physically members of your class, it would not be entirely wrong to think of them just as if they were. A friend declaration is itself a declaration so there's absolutely nothing to prevent you from defining it inline:

class year

{

// ...

friend std::ostream& operator<< (std::ostream& os, const year& y)

{

return os << y.m_data;

}

};

However, to keep your interface declaration "clean", it is best to place the implementation details outside the declaration, preferably alongside the other class member implementations.

Compound operators such as the increment-assign operator (+=) are often implemented as member functions, however there's no practical reason to do so, especially if you want to take advantage of implicit conversion. Use free functions wherever possible:

year& operator+= (year& lhs, const year& rhs)

{

lhs.m_data += rhs.m_data;

if (!lhs.m_data) throw std::range_error ("Error: no year zero!");

return lhs;

}

The above function must be declared a friend since it requires private access to the representation. However, note that you now have two places where you must check the invariant. Rather than duplicating the code, it would make sense to place that code in a private member function:

class year

{

// ...

private:

void check_invariants { if (!m_data) throw std::range_error ("Error: no year zero!"); }

};

Now the conversion constructor and increment assign operator can be simplified by calling this common method:

year::year (int64_t y): m_data {y} { check_invariants(); }

year& operator+= (year& lhs, const year& rhs)

{

lhs.m_data += rhs.m_data;

check_invariants();

return lhs;

}

With that done, all other increment operators can now be expressed in terms of this one overload without requiring friendship themselves:

// addition

year& operator+ (const year& lhs, const year& rhs)

{

return year {lhs} += rhs;

}

// prefix increment

year& operator++ (year& lhs)

{

return lhs += 1;

}

// postfix increment

year operator++ (year& lhs, const int)

{

year temp {lhs};

lhs += 1;

return temp;

}

All other operators can be implemented by the same means.

Remember, with the exception of the copy and move assignment operators, all other operator overloads should be implemented as free functions, with friend access only where required. Operators that are variations of each other (such as the increment operators), should be implemented in terms of one of those operators.

In some cases it can be helpful to provide a named member function in addition to or in place of an operator overload. For instance, the std::string& std::string::append (const std::string&) member function is synonymous with the std::string& operator+= (std:string&, const std::string&) operator overload. The first is implemented as a named member function, the second as a free function, where the free function simply invokes the member function. In cases where an operation might not be regarded as intuitive, a named member function is usually the best choice because the name can better express the notion of the operator than an operator alone can.

User Avatar

Wiki User

9y ago
This answer is:
User Avatar
More answers
User Avatar

Wiki User

14y ago

//This program shows overloading for the function Area(...). First time it's used to //calculate area of circle second one for square.

#include

using std::cin;
using std::cout;
using std::endl;
using std::setprecision;

double Area(double radius); //prototype for area of circle
double Area(double length, double width); //prototype for area of square

const double PI(3.142);

int main()
{
double radius(0.0);
cout << endl << "Enter radius: ";
cin >> radius;

double length(0.0);
cout << "Enter length: ";
cin >> length;
double width(0.0);
cout << "Enter width: ";
cin >> width;

cout << endl << "Area of circle is: " << setprecision(5) << Area(radius)
<< endl << "Area of square is: " << setprecision(5) << Area(length, width)
<< endl;

system("PAUSE");
return 0;
}

double Area(double radius)
{
return (PI*radius*radius);
}

double Area(double length, double width)
{
return (length * width);
}

This answer is:
User Avatar

User Avatar

Wiki User

12y ago

class Employee

{

public Employee(string name, int jobGrade){

Name = name;

JobGrade = jobGrade;

}

public string Name;

public int JobGrade;

public static bool operator <(Employee emp1, Employee emp2){

return Comparison(emp1, emp2) < 0;

}

public static bool operator >(Employee emp1, Employee emp2){

return Comparison(emp1, emp2) > 0;

}

public static bool operator ==(Employee emp1, Employee emp2){

return Comparison(emp1, emp2) emp2.JobGrade)

return 0;

else if (emp1.JobGrade > emp2.JobGrade)

return 1;

return 0;

}

}

This answer is:
User Avatar

User Avatar

Wiki User

12y ago

#include<iostream.h>

enum tot{A=1,a=2,b=3,K=4,c=5,d=6,Q=7,e=8,f=9,J=10,g=11,h=12,i=13};

enum black{club=14,spade=15};

enum red{dice=16,heart=17};

void score();

void score()

{

cout<<"\n\nYou are a winner\n";

cout<<"\nYour Score is : 300 Points\n";}

void main()

{

int ch;

cout<<"\n\n\t\t CARDS TO PLAY";

cout<<"\n\t\t *************";

cout<<"\n\n\n\t Welcome to LUCKY CARD GAME\n\n";

cout<<"\n\t1 2 3 4 5 6 7 8 9 10 11 12 13";

cout<<"\n\n Choose any number from above list : ";

cin>>ch;

switch(ch)

{

case 1:

int ch1;

cout<<"\n\n\nYou have choosen the card Ace\n";

cout<<"\n\nPlease select any other number :";

cout<<"\n\n\t\t14 15 16 17\n";

cin>>ch1;

switch(ch1)

{

case 14:

score();

break;

case 15:

score();

break;

case 16:

score();

break;

case 17:

score();

break;

}

break;

case 2:

cout<<"You are a losser";

cout<<"\n";

break;

case 3:

cout<<"You are a losser";

cout<<"\n";

break;

case 4:

int ch2;

cout<<"\n\n\nYou have choosen the card King";

cout<<"\n\n14 15 16 17\n";

cout<<"\n\nPlease select any other number :";

cin>>ch2;

switch(ch2)

{

case 14:

score();

break;

case 15:

score();

break;

case 16:

score();

break;

case 17:

score();

break;

}

break;

case 5:

cout<<"You are a losser";

cout<<"\n";

break;

case 6:

cout<<"You are a losser";

cout<<"\n";

break;

case 7:

int ch3;

cout<<"\n\n\nYou have choosen the card Queen";

cout<<"\n\n14 15 16 17\n";

cout<<"\n\nPlease select any other number :";

cin>>ch3;

switch(ch3)

{

case 14:

score();

break;

case 15:

score();

break;

case 16:

score();

break;

case 17:

score();

break;

}

break;

case 8:

cout<<"You are a losser";

cout<<"\n";

break;

case 9:

cout<<"You are a losser";

cout<<"\n";

break;

case 10:

int ch4;

cout<<"\n\n\nYou have choosen the card Jack";

cout<<"\n\nPlease select any other number :";

cout<<"\n\n14 15 16 17\n";

cin>>ch4;

switch(ch4)

{

case 14:

score();

break;

case 15:

score();

break;

case 16:

score();

break;

case 17:

score();

break;

}

break;

case 11:

cout<<"You are a losser";

cout<<"\n";

break;

case 12:

cout<<"You are a losser";

cout<<"\n";

break;

case 13:

cout<<"You are a losser";

cout<<"\n";

break;

default:

cout<<"Better luck next time!";

cout<<"\n";

break;

}

}

This answer is:
User Avatar

User Avatar

Wiki User

9y ago

If you want safety in enums, use an enum class rather than an ordinary enum. Ordinary enums can be implicitly converted to their underlying type whereas enum classes cannot. Enum classes are also scoped to their class, which avoids name-clashes when two enumerations have the same member.

This answer is:
User Avatar

User Avatar

Wiki User

10y ago

You cannot overload an operator using a function. Consider the following overload for the stream insertion operator to handle a reference to an object of type MyClass:

std::ostream& operator<< (std::ostream& os, MyClass& obj)

{

os << obj.m_data;

return os;

}

We'll assume MyClass::m_data is a primitive type such as int, char or float. If it were a user-defined type, we'd have to provide an overload for that type as well.

Note that 'operator<<' is not a function name, it is an operator. This means we can invoke it intuitively:

MyObject x;

std::cout << x;

If you attempt to overload this operator using a function, such as:

std::stream& insert(std::ostream& os, MyClass& obj)

{

os << obj.m_data;

return os;

}

You haven't actually overloaded the operator at all. All you've done is create an external function which means it must be invoked as an external function:

MyClass x;

std::cout << insert(std::cout, x);

Clearly there is no intuitiveness with this method of invocation. Even if you provided both overloads, the function isn't actually adding anything of any value because users will intuitively use the operator rather than the function, and may even question the purpose of the function.

Let's consider a template function for the addition operator:

template<typename T>

T add(T& a, T& b) { return a+b; }

Is add(a, b) any more intuitive than a+b? The fact that the implementation itself invokes operator+ through a+b means we must provide overloaded operators for all possible types T anyway. We're not adding anything of value by doing it this way because ultimately we're not actually overloading the operator, we're just creating external functions for no apparent reason.

This answer is:
User Avatar

User Avatar

Wiki User

11y ago

Function overloading is where the same function name is used with different signatures. The signature of a function is determined by the number and type of its parameters. Functions with the same name cannot differ by return type alone.

#include <iostream>

using namespace std;

// Overloaded functions:

int Max(int x, int y){ return(x>y?x:y); }

float Max(float x, float y){ return(x>y?x:y); }

int main()

{

int i1=1;

int i2=5;

cout << "The largest int is " << Max(i1,i2) << endl;

float f1=1.0;

float f2=1.5;

cout << "The largest float is " << Max(f1,f2) << endl;

return(0);

}

The previous example can be extended to provide overloads for all possible data types. However, since the implementations of every overload will be exactly the same, it would be better to template the arguments and provide just one implementation, as a function template. That way you can cater for all possible types (including user-defined types that have yet to be created) with a single function, and the compiler will generate all the required overloads for you, thus reducing code maintenance.

Overloading also caters for differing numbers of parameters, rather than merely by type.

#include <iostream>

using namespace std;

int Sum(int x, int y){ return(x+y); }

int Sum(int x, int y, int z){ return( x+y+z); }

int main()

{

int i1=1;

int i2=5;

int i3=7;

cout << "The sum of " << i1 << " and " << i2 << " is " << Sum(i1,i2) << endl;

cout << "The sum of " << i1 << ", " << i2 << " and " << i3 << " is " << Sum(i1,i2,i3) << endl;

return(0);

}

Again, the example is an over-simplification that could be better implemented as a single function with default values rather than as an overloaded function. However it serves to show that multiple functions with the same name can have different parameters and implementations. The compiler is able to determine which version of a function to call from the available prototypes (signatures).

This answer is:
User Avatar

Add your answer:

Earn +20 pts
Q: Write a C plus plus program for enumeration and function overloading?
Write your answer...
Submit
Still have questions?
magnify glass
imp
Continue Learning about Engineering

When to create a template function?

A template function is used when you want to write some kind of function that can be applied to different data types. It is a form of overloading, but you don't have to actually write all of the overloaded variants.


Write a program that read phrase and print the number of lower-case letter in it using function of counting?

write a program that reads a phrase and prints the number of lowercase latters in it using a function for counting? in C program


Write a Program to convert decimal number into hexadecimal no without using function and string?

This is not a question.


You are write a program that will read a list of number in the range from 1to n and will print for each number the corresponding term in cantor's enumeration as given no blank line should appear last?

see pages 43-49 in Principles of Program design by M. A. Jackson, 1975


1 Write a Java program to find x to the power y Use overloading for different cases when x and y are combination of integer and floating point numbers?

In practice, it is better to use the Math class, which already has a pow() (i.e., power) function. If you want to program it yourself, just write a loop:double myPower(double x, int y){double result = 1;for (int i = 1; i

Related questions

When to create a template function?

A template function is used when you want to write some kind of function that can be applied to different data types. It is a form of overloading, but you don't have to actually write all of the overloaded variants.


Where do we write main function in a c program?

Into the source program.


What is Re usability in java?

Reusability in Java means that once you write some code, you can use it over and over again - if you write it so that it can be reused. For example, if you write a Enumeration-Iterator adapter, or some code that lets you treat an Enumeration - Java legacy code - as an Iterator - shiny NEW Java code - then you can use it not only in your animal simulation program, but also in your Jacuzzi interface program.


Write a program that read phrase and print the number of lower-case letter in it using function of counting?

write a program that reads a phrase and prints the number of lowercase latters in it using a function for counting? in C program


Can you write a program without specifying the prototype of any function?

You can write a program without specifying its prototype when the function returns an integer.If the prototype is not mentioned the compiler thinks that the return type of the function used is integer.When making program which return integer you can ignore writing the protoype.


Write java program for addition of two objects?

May be link might help -&gt; http://www.allinterview.com/viewpost/408298.html There it is implemented through...... Operator Overloading!


Write a c program for matrix addition using function?

#include&lt;


Write a c program for function with no arguments and no return values?

void mynullfunction () {;}


How can I write a program to display prime numbers from 1 to 100?

Write a function that implements an algorithm that checks to see if a particular integer is prime (returning a boolean). Write a program that uses that function on each number from 1 to 100, and if true, displays that number.


Write a program in C without any functions?

It is not possible. In C, any program must have at least one function to be able to compile and execute properly: the function main()


How do you write a program that will call a function to multiply 4 numbers and return the answer to main program?

In Windows, use notepad.exe; in linux, use program xedit.


C coding for operator overloading?

C does not support operator overloading. If you mean C++ operator overloading, it depends on exactly what you wanted to do. If you wanted to '+' to strings, then you could write: string operator+(string a, string b) { // do something }