User Tools

Site Tools


Sidebar

projects

wcp1 (due 20240124)
pct0 (bonus; due 20240125)
pct1 (bonus; due 20240125)
abc0 (due 20240131)
pct2 (due 20240131)
wcp2 (due 20240131)
gtf0 (due 20240207)
pct3 (bonus; due 20240207)
wcp3 (due 20240207)
dtr0 (due 20240214)
pct4 (due 20240214)
wcp4 (due 20240214)
bwp1 (bonus; due 20240228)
mmf0 (due 20240228)
pct5 (bonus; due 20240228)
wcp5 (due 20240228)
cnv0 (due 20240306)
gfo0 (due 20240306)
pct6 (due 20240306)
wcp6 (due 20240306)
cnv1 (due 20240313)
fwg0 (due 20240313)
pct7 (bonus; due 20240313)
wcp7 (due 20240313)
fwg1 (due 20240320)
pct8 (due 20240320)
wcp8 (due 20240320)
pct9 (bonus; due 20240327)
wcp9 (due 20240327)
bwp2 (bonus; due 20240410)
fwg2 (due 20240410)
fwg3 (due 20240410)
gfo1 (due 20240410)
pctA (due 20240410)
wcpA (due 20240410)
cpp0 (due 20240417)
pctB (bonus; due 20240417)
wcpB (due 20240417)
cpp1 (due 20240424)
pctC (due 20240424)
wcpC (due 20240424)
pctD (bonus; due 20240501)
wcpD (bonus; due 20240501)
gfo2 (due 20240508)
pctE (bonus; due 20240508)
wcpE (bonus; due 20240508)
EoCE (due 20240516)
haas:spring2024:cprog:projects:oop2

Corning Community College

CSCS1320 C/C++ Programming

PROJECT: Object-Oriented Programming (OOP2)

Objective

Explore and implement a C++ program that utilizes polymorphism.

C++

Polymorphism

Polymorphism, in C++, refers to a hierarchy of classes which are all related through inheritance. This means that a call to a member function, will cause a different function to take place, depending on the type of object that calls the function.

Compile Time Polymorphism

Compile time polymorphism is achieved by overloading. This can be in the form of operator overloading, function overloading, or with templates.

Overloading is takes place when more than one function or operator, with the same name and scope, are given differing definitions. When this happens, the compiler will determine which definition is most appropriate, which is called overload resolution.

It is called compile-time polymorphism because a function is called at the time of program compilation.

Template Functions

Templates are used to create functions that work with multiple types. At compile time the compiler will substitute the template type with the type given at the function's call.

#include <cstdio>
 
struct Foo;
 
template<typename T>
const char* is_nullptr(T var)
{
	if (var == nullptr)
		return "nullptr";
	else
		return "NOT nullptr";
}
 
int main()
{
	int x{ 5 };
	int* xPtr{ &x };
	long* nullPtr{ nullptr };
	Foo* fooPtr{ nullptr };
 
	std::printf("xPtr is %s\n", is_nullptr(xPtr));
	std::printf("nullPtr is %s\n", is_nullptr(nullPtr));
	std::printf("fooPtr is %s\n", is_nullptr(fooPtr));
 
	return 0;
}

In this example you can call is_nullptr with any type, at compile time the compiler will create three separate functions: one that takes int pointers, one that takes long pointers, and one that takes Foo pointers.

This example produces this result:

xPtr is NOT nullptr
nullPtr is nullptr
fooPtr is nullptr

Templates help clean up your code and can be extremely powerful, especially when combined with type traits.

Run Time Polymorphism

Run time polymorphism is achieved by overriding. Overriding occurs when a child class redefines a parent class's member function.

In a runtime polymorphism, functions are called at the time of the program's execution.

Virtual Functions

Using the virtual keyword marks your functions as virtual. Virtual functions always call the most derived version of a member function.

#include <cstdio>
 
struct Rectangle
{
	const char* type() const { return "Rectangle"; }
};
 
struct Square : Rectangle
{
	const char* type() const { return "Square"; }
};
 
void print_type(const Rectangle& shape)
{
	std::printf("%s\n", shape.type());
}
 
int main()
{
	const Rectangle rect;
	const Square square;
 
	std::printf("Rectangle: ");
	print_type(rect);
	std::printf("Square: ");
	print_type(square);
 
	return 0;
}

Running this code produces this result:

Rectangle: Rectangle
Square: Rectangle

However, with the addition of the virtual keyword:

virtual const char* type() const { return "Rectangle"; }

We now get the desired result:

Rectangle: Rectangle
Square: Square

Notice objects deriving from Rectangle are passed by reference because if you pass by value a new Rectangle object will be created, therefore using Rectangle methods.

Access Control implications

Access control is important in polymorphism as it restricts or allows access to class members. Assigning public inheritance will allow all other classes and functions to inherit that data or function. Assigning Private inheritance will restrict access to a class member to functions within that same class. The only exception taking place when a class is declared as a “friend.” Protected is similar to private, with the exception that protected class members can also be accessed by derived classes.

Parent-Child Relationships

Parent child relationships refer to base classes and the derived classes that inherit from them. In regards to polymorphism, this means, that the derived classes are not simply inheriting attributes or methods, but using them in different ways. The methods and attributes being inherited still depends on that element's access control label.

Inheritance lets us inherit attributes and methods from another class. Polymorphism uses those methods to perform different tasks.

Similarities to word origins

It is strange that what is called 'polymorphism' in C++ is called such. Polymorph's word structure would imply multiple shapes, and polymorph in common fantasy/magical settings often relates to something temporarily transforming into a different creature, or shape. This has no relation to the C++ polymorph, which mainly relates to a child class changing an already existing function of its parent classes. It seems that mutation or evolution would be a better term, as if a creature inherited something from its ancestors, such as eyes, and then the child some genetic variation that caused its eyes to be more effective at seeing, that would be a mutation or evolution, we would not call such a thing polymorphing.

COOL BUG FACT: After writing this I found that “polymorph” and “polymorphism” have two very different meanings. Polymorphism is the occurrence of different forms among members of a colony, meaning everything I wrote above this is kinda wrong…

RELEVANT COOL BUG FACT: If the child class has a child of its own, the polymorphed version of functions will be what the child's child inherits

Program

Write a program that makes use of polymorphism. It can be anything, so long as you genuinely implement it and it works.

Be sure to make use of and follow proper conventions having public, protected, and private access control (no cheating by making everything public), and demonstrate polymorphism.

Have a main() function that instantiates an instance of your chosen theme of class with polymorphism, and runs that instantiated object through a range of tests demonstrating the class works as intended (likely also prompting the user to input any needed values to configure the attributes of the object).

References

Submission

I'll be looking for the following:

104:oop2:final tally of results (104/104)
*:oop2:no compiler messages, program compiles and runs without issue [52/52]
*:oop2:specified functionality is implemented [52/52]

Additionally:

  • Solutions not abiding by SPIRIT of project will be subject to a 50% overall deduction
  • Solutions not utilizing descriptive why and how COMMENTS will be subject to a 50% overall deduction
  • Solutions not utilizing INDENTATION to promote scope and clarity will be subject to a 50% overall deduction
  • Solutions lacking ORGANIZATION and are not easy to read (within 90 char width) are subject to a 50% overall deduction
haas/spring2024/cprog/projects/oop2.txt · Last modified: 2023/04/10 23:27 by 127.0.0.1