My understanding of polymorphism

  • (2 Pages)
  • +
  • 1
  • 2

18 Replies - 1112 Views - Last Post: 04 July 2012 - 09:16 AM Rate Topic: -----

#1 Beweren   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 23
  • Joined: 25-September 11

My understanding of polymorphism

Posted 02 July 2012 - 08:36 AM

Hello everybody.

I have a very specific problem, which leads to the more fundamental understanding of the polymorphism - At least I think so.

I am making a employee-handling program from an assignment in a book. I am to make a superclass or should I say interface called Employee. This superclass has three child-classes which has some additional member variables.

In my main file, I keep the employees in a vector (vector<Employee>) variable. At some point I want to make it possible to delete employees from the vector.

The way I wanted to do that is to print out the containment of my vector, and then let the user pick the employee to be deleted.

Employee.h
#ifndef EMPLOYEE_H
#define EMPLOYEE_H

#include <string>
#include <iostream>
#include <fstream>

class Employee
{
    public:
		virtual ~Employee();

    protected:
        Employee();
		void informMeNow();
		void printToFile(std::ostream& file);
        
        std::string eFirstname;
        std::string eLastname;
        int eSalary;

        

    private:
};

#endif // EMPLOYEE_H



This header has no interesting implementation.

One of the subclasses header file:
Engineer.h:
#pragma once
#include "employee.h"

enum engineerType {mechanical, electric, software};

class Engineer : public Employee
{
	public:
		Engineer(void);
		~Engineer(void);

		void informMeNow();
		void printToFile(std::ostream& file); 

	private:
		engineerType engType;
		bool knowsCpp;
		int yearsOfExperience;

};



The Engineers implementation:
Engineer.cpp:
#include "Engineer.h"

using namespace std;

Engineer::Engineer(void)
{
	int choice = 0;

	while(choice < 1 || choice > 3)
	{
		cout << "Engineer is either mechanical, electric or software. Enter 1, 2 or 3: "; cin >> choice;
		switch(choice)
		{
		case 1:
			engType= mechanical;
			break;

		case 2:
			engType= electric;
			break;

		case 3:
			engType = software;
			break;

		default:
			cout << "You dumbfuck!" << endl;
			cout << "You need to enter one of three numbers! don't bug me again!" << endl;
			cout << "Try again!" << endl;
			break;
		}
	}

	cout << "How many years of experience does this engineer have?: "; cin >> yearsOfExperience;
	cout << "Does this engineer know c++? 'true' or 'false': "; cin >> knowsCpp;
	


}


Engineer::~Engineer(void)
{
	//No dynamic memory to free
}

void Engineer::printToFile(ostream& file)
{
	file << "------------------------------------------------" << endl;
	file << "Name: " << eFirstname + " " + eLastname << endl;
	file << "Salary: " << eSalary << endl;
	file << "This engineer handles the " << engType << " area" << endl;
	file << "This enginner knows C++: " << knowsCpp << endl;
	file << "This engineer has " << yearsOfExperience << " years of experience." << endl;
	file << "------------------------------------------------" << endl << endl;
}

void Engineer::informMeNow()
{
	cout << "------------------------------------------------" << endl;
	cout << "Name: " << eFirstname + " " + eLastname << endl;
	cout << "Salary: " << eSalary << endl;
	cout << "This engineer handles the " << engType << " area" << endl;
	cout << "This enginner knows C++: " << knowsCpp << endl;
	cout << "This engineer has " << yearsOfExperience << " years of experience." << endl;
	cout << "------------------------------------------------" << endl << endl;
}



The main file:
main.cpp:
#include <vector>

//include custom classes
#include "Manager.h"
#include "Engineer.h"
#include "Reseacher.h"
#include "Employee.h"

using namespace std;

int main()
{
	vector<Employee> employees;
	bool isRunning = true;
	int menuChoice = 0;
	
	cout << "*** EMPLOYEE MANAGING SYSTEM ***" << endl << endl;

	while(isRunning)
	{
		cout << endl;
		cout << "/// *** MENU *** ///" << endl;
		cout << "1) Add an employee, 2) Delete an employee, 3) Save to Database" << endl; cin >> menuChoice;

		switch(menuChoice)
		{
			case 1:
				int employeeChoice;
				cout << "1) Manager, 2) Engineer, 3) Reseacher: "; cin >> employeeChoice;
				switch(employeeChoice)
				{
					case 1:
						employees.push_back(Manager());
						break;
					case 2:
						employees.push_back(Engineer());
						break;
					case 3:
						employees.push_back(Reseacher());
						break;
					default:
						cout << "choice not possible!" << endl << endl;
						break;
				}
				break;

			case 2:

					// enter delete algorithm.
					int deleteChoice;

					cout << "Press enter to get the list of employees!";
					system("pause");
				
					for(unsigned int i= 0; i < employees.size(); i++)
					{
						employees[i].informMeNow();
					}
				
					cout << endl;
					cout << "Enter integer of employee to delete: ";
					cin  >> deleteChoice; 

					employees.erase( employees.begin() + deleteChoice );

					break;

			default:
				return 1;
				break;
		}
	}

	
	system("pause");
	return 1;
}



This will not compile, because of the " employees[i].informMeNow() " line. I get an error whether the informMeNow() function is protected or public - which confuses me. I though that the polymorphic system would search down the hierarchy of inheritance for an equevalent public function?
I tried several other things, which I can't really remember now.

How do I access the informMeNow() function from a vector containing supers. ? I must have got the theory behind polymorphism all wrong, because this has given me a headache.

Could You please tell me what I am missing.

(Be aware that the main file is unfinished!)

Thank you in advance :)
Beweren

Is This A Good Question/Topic? 0
  • +

Replies To: My understanding of polymorphism

#2 vividexstance   User is offline

  • Tiocfaidh ár lá
  • member icon

Reputation: 792
  • View blog
  • Posts: 2,873
  • Joined: 31-December 10

Re: My understanding of polymorphism

Posted 02 July 2012 - 08:57 AM

Your vector of Employees should be a vector of pointers to Employees. The reason for this is because that's how polymorphism works. If you want to place Engineers or any Employee derived class into the vector, it must be a pointer or reference.

*EDIT*: When you go to push an Employee onto the vector, you need to push a pointer, so just calling the default constructor inside the push_back() call won't be enough. I don't know if you have learned dynamic memory allocation yet, but usually you would just do something like:
employees.push_back(new Engineer);

One thing to note though is that you need to cleanup the vector now once you're done with it. This is a simple task however:
for(int i = 0, end = employees.size(); i < end; ++i)
    delete employees[i];


This post has been edited by vividexstance: 02 July 2012 - 09:01 AM

Was This Post Helpful? 1
  • +
  • -

#3 Aphex19   User is offline

  • Born again Pastafarian.
  • member icon

Reputation: 619
  • View blog
  • Posts: 1,873
  • Joined: 02-August 09

Re: My understanding of polymorphism

Posted 02 July 2012 - 09:03 AM

In your Employee class, informMeNow and printToFile should be declared virtual if you want them to be overridden in derived classes. Since they aren't overridden, the base classes methods will be called, and they're protected, hence inaccessible.

Also, do you need to use an Employee object directly, or are you planning on only using Employee as an interface class? If the latter, consider making it an abstract class (using pure virtual methods).

This post has been edited by Aphex19: 02 July 2012 - 09:13 AM

Was This Post Helpful? 1
  • +
  • -

#4 Beweren   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 23
  • Joined: 25-September 11

Re: My understanding of polymorphism

Posted 02 July 2012 - 09:39 AM

Wow This is enlightening.

@VividExtsance -> I did learn about dynamic memory, so I think I know how it works. The pointer and referencing system is kinda difficult for me right now to understand (I have a degree in computer science, but we've mostly used Java and Assembly to program, which concerns me a bit, since c++ is such a powerful language.) Java is a bit of a retarded language compared to C++, i think.
- Thank you so much for your help :-D

@Aphex19 - > You might be right! Will this ensure that the compiler finds the derived version of the function, you think?

Thank you so much guys for being patient with noobs like me..
Was This Post Helpful? 0
  • +
  • -

#5 Aphex19   User is offline

  • Born again Pastafarian.
  • member icon

Reputation: 619
  • View blog
  • Posts: 1,873
  • Joined: 02-August 09

Re: My understanding of polymorphism

Posted 02 July 2012 - 09:46 AM

View PostBeweren, on 02 July 2012 - 05:39 PM, said:

Java is a bit of a retarded language compared to C++, i think.


I can empathise with you to a degree. I have never had much of an appreciation for Java, for what I believe are legitimate reasons.

View PostBeweren, on 02 July 2012 - 05:39 PM, said:

Will this ensure that the compiler finds the derived version of the function, you think?

Thank you so much guys for being patient with noobs like me..


If you want your methods to be overridden in derived classes, they must be declared as virtual in the base class. You can also make a pure virtual method, which makes the class abstract, meaning that it cannot be instantiated. This is useful when your base class is just an interface (like Employee seems to be in your case).

You're very welcome.

This post has been edited by Aphex19: 02 July 2012 - 09:49 AM

Was This Post Helpful? 0
  • +
  • -

#6 vividexstance   User is offline

  • Tiocfaidh ár lá
  • member icon

Reputation: 792
  • View blog
  • Posts: 2,873
  • Joined: 31-December 10

Re: My understanding of polymorphism

Posted 02 July 2012 - 09:51 AM

To make a function and therefore a class a pure virtual abstract class, you just need to make one of the functions "pure". You do it like this:
class Pure
{
public:
    Pure() {}
    virtual ~Pure() {}

    virtual void run() = 0;
};


Do you see the "= 0;" part at the end of run() function declaration? Also the function is virtual as well. So a pure virtual function is one that is virtual and it has "= 0;" at the end of the declaration. Like Aphex said, if you do this, you will not be able to create objects of type Employee, only classes that are derived from Employee will have the ability to be created.

This post has been edited by vividexstance: 02 July 2012 - 09:51 AM

Was This Post Helpful? 0
  • +
  • -

#7 Beweren   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 23
  • Joined: 25-September 11

Re: My understanding of polymorphism

Posted 02 July 2012 - 09:54 AM

I could modify it, so that it would be. But right now, the compiler runs the employee constructer first, and then the derived constructer afterwards. Will this be a problem if I make a vector containing pointers?

employee.cpp:

#include "Employee.h"
using namespace std;

Employee::Employee(void)
{
	cout << "***EMPLOYEE***" << endl;
	cout << "First name: "; cin >> eFirstname; 
	cout << "Last name: "; cin >> eLastname; 
	cout << "Monthly Salary: "; cin >> eSalary;  
}


Employee::~Employee(void)
{
	// no dynamic memory to free
}



?
Was This Post Helpful? 0
  • +
  • -

#8 Aphex19   User is offline

  • Born again Pastafarian.
  • member icon

Reputation: 619
  • View blog
  • Posts: 1,873
  • Joined: 02-August 09

Re: My understanding of polymorphism

Posted 02 July 2012 - 10:15 AM

View PostBeweren, on 02 July 2012 - 05:54 PM, said:

I could modify it, so that it would be. But right now, the compiler runs the employee constructer first, and then the derived constructer afterwards. Will this be a problem if I make a vector containing pointers?


Declaring a pointer to an Employee won't instantiate it and so won't call the constructor. Only instantiating a class will call the constructor. I'm not sure what the ramifications will be in your case though.

This post has been edited by Aphex19: 02 July 2012 - 10:17 AM

Was This Post Helpful? 0
  • +
  • -

#9 axnjxn   User is offline

  • D.I.C Head

Reputation: 14
  • View blog
  • Posts: 144
  • Joined: 04-February 12

Re: My understanding of polymorphism

Posted 02 July 2012 - 10:16 AM

Can't he use an Employee pointer to subclass?

/* using the abstract superclass pointer to an implemented subclass
   will allow you to store all your different subclasses in the same
   vector which is initialized to hold Employee pointers */
Employee *em1 = new Engineer(); 
Employee *em2 = new Manager();
Employee *em3 = new Researcher();
employees.push_back(em1);
employees.push_back(em2);
employees.push_back(em3);



One of you masters jump in here and correct me if I'm wrong. This will call both the superclass and subclass constructors, correct?

This post has been edited by axnjxn: 02 July 2012 - 10:17 AM

Was This Post Helpful? 0
  • +
  • -

#10 vividexstance   User is offline

  • Tiocfaidh ár lá
  • member icon

Reputation: 792
  • View blog
  • Posts: 2,873
  • Joined: 31-December 10

Re: My understanding of polymorphism

Posted 02 July 2012 - 10:55 AM

It depends on the constructor for the specific class being executed. Also, when using dynamically allocated memory, you need to remember to clean up the storage when you're done using it. Most modern OS'es will do this for you but it's still a good habit to get into.
Was This Post Helpful? 0
  • +
  • -

#11 axnjxn   User is offline

  • D.I.C Head

Reputation: 14
  • View blog
  • Posts: 144
  • Joined: 04-February 12

Re: My understanding of polymorphism

Posted 02 July 2012 - 11:10 AM

Quote

Also, when using dynamically allocated memory, you need to remember to clean up the storage when you're done using it. Most modern OS'es will do this for you but it's still a good habit to get into.

Understood. This is advice that should be reiterated often. Memory leaks still occur.

Quote

It depends on the constructor for the specific class being executed.

Can you clarify this? Do you mean something like this:
//constructor
SubClass::SubClass() : SuperClass() {
 
}


Where the base class constructor is called explicitly by the subclass constructor?

This post has been edited by axnjxn: 02 July 2012 - 11:11 AM

Was This Post Helpful? 0
  • +
  • -

#12 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6221
  • View blog
  • Posts: 21,472
  • Joined: 05-May 12

Re: My understanding of polymorphism

Posted 02 July 2012 - 11:10 AM

View Postvividexstance, on 02 July 2012 - 10:55 AM, said:

Also, when using dynamically allocated memory, you need to remember to clean up the storage when you're done using it. Most modern OS'es will do this for you but it's still a good habit to get into.


With the caveat that the OS will do the clean up after your program is finished running. While it's running, it's leaking memory.
Was This Post Helpful? 0
  • +
  • -

#13 vividexstance   User is offline

  • Tiocfaidh ár lá
  • member icon

Reputation: 792
  • View blog
  • Posts: 2,873
  • Joined: 31-December 10

Re: My understanding of polymorphism

Posted 02 July 2012 - 11:19 AM

I misspoke when I said that it depended on which constructor was being executed. I don't know why but I thought for some reason that it mattered if the base class' constructor was explicitly called in the derived class' constructor like so:
class Base
{
    int n;
public:
    Base(int nn) { /* ... */ }
};

class Derived : public Base
{
public:
    Derived(int nn) : Base(nn) { /* ... */ }
};


It doesn't matter though, if you don't call the base class constructor explicitly in the derived class' constructor, the default constructor for the base class will be invoked either way.

To SkyDiver, I was just pointing out the fact that operating systems do take care of memory allocation/deallocation for you. I also said that cleaning up dynamically allocated storage yourself is a good habit to get into even though the OS will do it for you.
Was This Post Helpful? 0
  • +
  • -

#14 Bench   User is offline

  • D.I.C Lover
  • member icon

Reputation: 944
  • View blog
  • Posts: 2,464
  • Joined: 20-August 07

Re: My understanding of polymorphism

Posted 02 July 2012 - 11:19 AM

View PostSkydiver, on 02 July 2012 - 07:10 PM, said:

View Postvividexstance, on 02 July 2012 - 10:55 AM, said:

Also, when using dynamically allocated memory, you need to remember to clean up the storage when you're done using it. Most modern OS'es will do this for you but it's still a good habit to get into.


With the caveat that the OS will do the clean up after your program is finished running. While it's running, it's leaking memory.

Worse than that - if you rely on the OS to clean up memory after the program terminates, the program may just run on for too long and eventually crash with an out-of-memory exception. Even if the program does terminate before this happens, your objects will never be destroyed, meaning that other resources which aren't ultimately controlled by the OS may still be leaked. It's never OK to allocate memory dynamically without employing some kind of mechanism which will properly destroy an object and release its memory. The preferred solution is to use shared_ptr or unique_ptr, which do the clean-up for you.
Was This Post Helpful? 0
  • +
  • -

#15 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6221
  • View blog
  • Posts: 21,472
  • Joined: 05-May 12

Re: My understanding of polymorphism

Posted 02 July 2012 - 11:41 AM

View Postvividexstance, on 02 July 2012 - 11:19 AM, said:

To SkyDiver, I was just pointing out the fact that operating systems do take care of memory allocation/deallocation for you. I also said that cleaning up dynamically allocated storage yourself is a good habit to get into even though the OS will do it for you.


I figured that's what you meant. :lol: I just didn't want the OP to have the impression that dynamic garbage collection happens while the C/C++ program was running. I wanted to make it clear that the memory deallocation would happen at program termination time.

You gave great advice about getting into a good habit of cleaning up any resources used.
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2