Polymorphism Intro CPP
Polymorphism Intro CPP
Polymorphism
Define polymorphism
Overload a function
Override a function
What is Polymorphism?
Polymorphism is a concept in object-oriented programming in which a
single interface takes different forms (polymorphism means “many
forms”). Often this means similar operations are grouped together with the
same name. However, these operations with the same name will produce
different results. You have already encountered a few examples of
polymorphism. Enter the following code into the IDE.
int a = 5;
int b = 10;
cout << (a + b) << endl;
string c = "5";
string d = "10";
cout << (c + d) << endl;
bool e = true;
bool f = false;
cout << (e + f) << endl;
Notice how the plus operator (+) can add together two numbers,
concatenate two strings, and add two booleans. You have a single interface
(the plus operator) taking different forms — one that works with integers,
another that works with strings, and even one that works with booleans.
This is an example of polymorphism.
Operator Overloading
Because the plus operator can work with different forms, we can say that it
is overloaded. C++ overloads this operator by default. However, a user
cannot manually overload an operator.
challenge
int a = 5;
string b = "true";
cout << (a + b) << endl;
Function Overriding
Function overriding is another example of polymorphism that you have
already seen. Overriding a function means that you have two functions
with the same name, but they perform different tasks. Again you see a
single interface (the function name) being used with different forms (the
base class and the derived class). Create the following classes.
//add class definitions below this line
class Alpha {
public:
void Show() {
cout << "I am from class Alpha" << endl;
}
};
Alpha test_object;
test_object.Show();
As expected, the script prints I am from class Alpha. Now change the line
of code in which you instantiate the object test_object to a Bravo object
like below. Make no other changes and run the code again.
Bravo test_object;
Now the script prints I am from class Bravo. The function call did not
change, but the output did. A single interface (the Show function) works
with multiple forms (the Alpha and Bravo data types). This is why function
overriding is an example of polymorphism.
challenge
Solution
class Alpha {
public:
void Show() {
cout << "I am from class Alpha" << endl;
}
void Hello() {
cout << "Hello from Alpha" << endl;
}
};
void Hello() {
cout << "Hello from Bravo" << endl;
}
};
int main() {
return 0;
}
Function Overloading
Function Overloading
Function overloading is another example of polymorphism. Function
overloading occurs when you have a single function name that can take
different sets of parameters. Imagine you want to write the function Sum
that can sum up to three numbers. The math involved with three
parameters is slightly different than two parameters, which is different
from 1 parameter, etc. Traditionally, if you declare a function that takes
three parameters but only pass two, C++ will throw an error message.
Instead, let’s create a class that has two Sum functions; one with two
parameters and another with three parameters.
class TestClass {
public:
int Sum(int n1, int n2, int n3) {
return n1 + n2 + n3;
}
Create an object of type TestClass and call both versions of the Sum
function. Be sure you are passing three arguments for one function and
two arguments for the other.
TestClass tc;
cout << tc.Sum(1, 2, 3) << endl;
cout << tc.Sum(1, 2) << endl;
challenge
Solution
//add class definitions below this line
class TestClass {
public:
int Sum(int n1, int n2, int n3, int n4, int n5) {
return n1 + n2 + n3 + n4 + n5;
}
int main() {
TestClass tc;
cout << tc.Sum(1, 2, 3, 4, 5) << endl;
cout << tc.Sum(1, 2, 3, 4) << endl;
cout << tc.Sum(1, 2, 3) << endl;
cout << tc.Sum(1, 2) << endl;
return 0;
class Person {
public:
Person() {}
string Info() {
return (name + " lives at " + to_string(number) + ' ' +
street + '.');
}
private:
string name;
int number;
string street;
};
When you create a Person object with no arguments, the Info function still
works. However, the information that is printed may look jarring since C++
will use left-over “junk” memory data to fill in for variables that are not
initialized. You can also instantiate an object with three arguments. Like
function overloading, constructor overloading is a form of polymorphism.
Person p1;
Person p2("Calvin", 37, "Main Street");
cout << p1.Info() << endl;
cout << p2.Info() << endl;
Random Values
Unlike other programming languages, C++ does not automatically initialize
variables that are not initialized by the user. This is done to preserve
memory. Thus, you might get “randomly” generated data for certain
uninitialized variables. Run the code several more times and you’ll notice
different values will be printed.
challenge
class Person {
public:
//Person() {}
string Info() {
return (name + " lives at " + to_string(number) + " "
+ street + ".");
}
private:
string name;
int number;
string street;
};
Person p1;
//Person p2("Calvin", 37, "Main Street");
cout << p1.Info() << endl;
//cout << p2.Info() << endl;
class Person {
public:
//Person() {}
string Info() {
return (name + " lives at " + to_string(number) + " "
+ street + ".");
}
private:
string name;
int number;
string street;
};
Abstract Classes
Another form of polymorphism in C++ involves abstract functions. These
functions, however, require knowledge of abstract classes. So before we
continue the discussion on polymorphism, we need to first talk about
abstract classes.
Concrete Classes
Any class that is not an abstract class is considered to be a concrete class.
You do not need to use a keyword to indicate that a class is concrete.
class Shape {
public:
virtual double Area() = 0;
};
As seen in the above code, the virtual function Area is defined as being
equal to 0. We do this because we expect classes that are derived from
Shape to have Area functions that behave differently. For example,
calculating the area of a Triangle object is different from calculating the
area of a Rectangle object. Thus, we define Area as an abstract function in
the base class Shape. Note that when you redefine abstract functions in the
derived classes, you do not include the virtual keyword nor assign the
function to 0. Let’s define our classes further.
class Shape {
public:
virtual double Area() = 0;
double GetBase() {
return base;
}
double GetHeight() {
return height;
}
protected:
double base;
double height;
};
double Area() {
return base * height / 2;
}
};
double Area() {
return base * height;
}
};
You can see above that two classes are derived from Shape, the Triangle
class and the Rectangle class. Also notice how Shape contains additional
getters and setters as well as protected attributes. We encapsulate them as
protected in order for our derived classes to access them. This way, we
don’t have to declare additional attributes in Triangle and Rectangle.
As expected, the code returns the correct calculations for the Triangle and
Rectangle objects.
challenge
Shape s;