Please help me understand why I'm doing this inheritance problem wrong.

Hello! Please help me understand the concept of inheritance. Actually, I'm not even sure inheritance is what I'm trying to do here. Let me explain: Suppose I have a class Vehicle that is inherited by two classes Car and Bicycle:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Vehicle {
	public: 
		Vehicle() { 
			// ...
		}
		~Vehicle() {
			// ...
		}

};

// A Bicycle IS A Vehicle
class Bicycle : Vehicle {
	public:
		Bicycle() { /* … */ }
		~Bicycle() { /* … */ }
		void Stop() { /* … */ }
		void Go(int feet) { /* … */}
		void TurnLeft() { /* … */ }
		void TurnRight() { /* … */ }
	private:
		/* … */
};

// A Car IS A Vehicle
class Car : Vehicle {
	public: 
		Car();
		~Car();
		void Stop() {  /* … */ }
		void Go(int miles) { /* … */ }
		void TurnLeft() { /* … */ }
		void TurnRight() { /* … */ }
	private:
		/* … */

};


Now, both Cars and Bicycles can Stop, Go, and Turn, but they both do all of those actions in different ways (this is why we cannot put them in the base class; we put them in the derived ones because they have separate implementations).

However, we can define outside functions that only utilize their public member functions, and that's all they need; these functions can handle either a Car or a Bicycle. It doesn't care what kind of a vehicle it is, because the path to get to work or to the mall is the same:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void GoToWork(Vehicle AnyVehicle)
{
	AnyVehicle.TurnLeft();
	AnyVehicle.Go(2);
	AnyVehicle.TurnRight();
	return;
}

void GoToTheMall(Vehicle AnyVehicle)
{
	AnyVehicle.TurnRight();
	AnyVehicle.Go(3);
	AnyVehicle.TurnRight();
	AnyVehicle.Go(1);
	AnyVehicle.TurnLeft();
	return;
}


Unfortunately, the problem with this is that it doesn't work:

1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
	Bicycle MyBike;

	// ERROR: Expects a Vehicle... and gets a Vehicle?!?!?!
	GoToWork(MyBike); 
	
	Car MyCar;
	GoToTheMall(MyCar);
 
	return 0;
}


My question is: why doesn't this work? On the call to GoToWork the compiler tries to convert MyBike to a Vehicle and fails. But MyBike is a Vehicle!
Correct, the functions will expect a Vehicle. In your MAIN function, you need to create a pointer of type VEHICLE, and then assign MyBike/MyCar to that pointer, like so:

1
2
3
4
5
6
7
8
9
10
11
12
Vehicle* MyVehicle;

Bicycle MyBike;
Car MyCar;

MyVehicle = &MyBike;
GoToWork(MyVehicle); 

MyVehicle = &MyCar;
GoToTheMall(MyVehicle);
 
return 0;


In GotoWork/GoToMall, you also need to replace Vehicle AnyVehicle (in the argument list) with Vehicle* AnyVehicle. (Vehicle - asterisk, space - AnyVehicle) In those functions, replace all the dots with ->. (That's a hyphen followed immediately by a "greater than" sign.)

Hopefully this works for you - let me know if not.
Last edited on
Thanks for your help, but unfortunately it did not work. It still is looking for functions TurnLeft(), TurnRight(), etc. in the base class. Here is my code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

#include <iostream>

class Vehicle {
	public: 
		Vehicle() { 
			// ...
		}
		~Vehicle() {
			// ...
		}

};

// A Bicycle IS A Vehicle
class Bicycle : Vehicle {
	public:
		Bicycle() { }
		~Bicycle() { }
		void Stop() { }
		void Go(int feet) { }
		void TurnLeft() { }
		void TurnRight() { }
};

// A Car IS A Vehicle
class Car : Vehicle {
	public: 
		Car();
		~Car();
		void Stop() { }
		void Go(int feet) { }
		void TurnLeft() { }
		void TurnRight() { }

};

void GoToWork(Vehicle* AnyVehicle);
void GoToTheMall(Vehicle* AnyVehicle);

int main()
{
	// MyVehicle is a pointer to a Vehicle.
	Vehicle* MyVehicle;

	Bicycle MyBike;
	
	// MyVehicle assigned to the address of MyBike
	MyVehicle = &MyBike;

	GoToWork(MyVehicle); 
	
	Car MyCar;

	MyVehicle = &MyCar;
	GoToTheMall(MyVehicle);
 
	return 0;
}

void GoToWork(Vehicle* AnyVehicle)
{
	AnyVehicle->TurnLeft();
	AnyVehicle->Go(2);
	AnyVehicle->TurnRight();
	return;
}

void GoToTheMall(Vehicle* AnyVehicle)
{
	AnyVehicle->TurnRight();
	AnyVehicle->Go(3);
	AnyVehicle->TurnRight();
	AnyVehicle->Go(1);
	AnyVehicle->TurnLeft();
	return;
}


ETA: Actually, scratch that: The first error actually occurs at MyVehicle = &MyBike;. "Conversion from Bicycle* to Vehicle* exists, but is inaccessible."
Last edited on
First - I missed this on first examination of your code, but I believe you need "public" in your Car/Bike definitions. Instead of this:

class Bicycle : Vehicle

Try this:

class Bicycle : public Vehicle

Regarding the other issue, it doesn't look like you have actually defined the functions such as "TurnRight," "TurnLeft," and "Go." Create those functions - even blank ones, like the example below - and it should compile.

1
2
3
4
void Bicycle::TurnRight(void)
{

}
You're both missing the virtual function in the base class.

1
2
3
4
5
6
7
8
9
10
11
12
13
class Vehicle {
public: 
    Vehicle() { 
        // ...
    }
    ~Vehicle() {
        // ...
    }
    virtual void Stop() = 0;
    virtual void Go (int  feet) = 0;
    virtual void TurnLeft() = 0;
    virtual void TurnRight() = 0;
};


Once you work that out, you should be able to fix up the rest of your bugs pretty quickly.

http://www.cplusplus.com/doc/tutorial/polymorphism/
OK looks like I'm in the clear, but I do have a couple more questions. Here is my code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <iostream>

class Vehicle {
	public: 
		Vehicle() { 
			std::cout << "Creating a Vehicle...\n";
		}
		~Vehicle() {
			std::cout << "Destroying a Vehicle...\n";
		}
		virtual void Stop() = 0;
		virtual void Go(int feet) = 0;
		virtual void TurnLeft() = 0;
		virtual void TurnRight() = 0;

};

// A Bicycle IS A Vehicle
class Bicycle : public Vehicle {
	public:
		Bicycle() { std::cout << "Creating a Bicycle...\n"; }
		~Bicycle() { std::cout << "Destroying a Bicycle...\n"; }
		void Stop() { std::cout << "Bicycle stopping...\n"; }
		void Go(int miles) { std::cout << "Bicycle going " << miles << " miles...\n";}
		void TurnLeft() { std::cout << "Bicycle turning left...\n"; }
		void TurnRight() { std::cout << "Bicycle turning right...\n"; }
	private:
		;
};

// A Car IS A Vehicle
class Car : public Vehicle {
	public: 
		Car() { std::cout << "Creating a car...\n"; }
		~Car() { std::cout << "Destroying a car...\n"; }
		void Stop() { std::cout << "Car stopping...\n"; }
		void Go(int miles) { std::cout << "Car going " << miles << " miles...\n"; }
		void TurnLeft() { std::cout << "Car turning left...\n"; }
		void TurnRight() { std::cout << "Car turning right...\n"; }
	private:
		;
};

void GoToWork(Vehicle* AnyVehicle)
{
	AnyVehicle->TurnLeft();
	AnyVehicle->Go(2);
	AnyVehicle->TurnRight();
	return;
}

void GoToTheMall(Vehicle* AnyVehicle)
{
	AnyVehicle->TurnRight();
	AnyVehicle->Go(3);
	AnyVehicle->TurnRight();
	AnyVehicle->Go(1);
	AnyVehicle->TurnLeft();
	return;
}

int main()
{
	Vehicle* MyVehicle = new Bicycle();

	GoToWork(MyVehicle); 
	
	delete MyVehicle;

	MyVehicle = new Car();

	GoToTheMall(MyVehicle);

	delete MyVehicle; 
	std::cin.get();
	return 0;
}


...and here is my output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Creating a Vehicle...
Creating a Bicycle...
Bicycle turning left...
Bicycle going 2 miles...
Bicycle turning right...
Destroying a Vehicle...
Creating a Vehicle...
Creating a car...
Car turning right...
Car going 3 miles...
Car turning right...
Car going 1 miles...
Car turning left...
Destroying a Vehicle...


Questions:
1. I've read that the destroctor of a Base class should always be virtual. Well here I did that and it didn't change anything. Why (or when) should I do that?
2. As you can see, I changed the main() function a bit so that these objects get created "on the heap". But that adds danger in that if I don't delete them I get memory leaks. What is the advantage of doing it this way?
1) Destructors of abstract base classes should be virtual because if you destroy the base class without destroying the actual object, you have a memory leak. Note in your output that it destroyed "a Vehicle" but it never destroyed a car or a bicycle, like in the destructors for the child classes. You have programmed a memory leak into your code (one of the "other bugs" that I mentioned).
2) The advantage of creating objects on the heap is that you can dynamically create them. Take this code, for example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
character * newCharacter();

class characterSet {
	vector<int> x;
	list<character*> characters;
	list<character*>::iterator it;
	character *temp;
	string name;
	int selection, dice, tempInt;
	ofstream mySaveFile;
	ifstream myOpenFile;
public:
	void showMenu();
};

void characterSet::showMenu(){
	cout << "***************************" << endl;
	cout << "*  Make a selection:      *" << endl;
	cout << "*    1) New Character     *" << endl;
	cout << "*    2) Delete Character  *" << endl;
	cout << "*    3) Save Characters   *" << endl;
	cout << "*    4) Open Characters   *" << endl;
	cout << "*    5) Print Characters  *" << endl;
	cout << "*    6) Roll Dice         *" << endl;
	cout << "*    0) Exit              *" << endl;
	cout << "***************************" << endl;
	cout << "Menu$ ";
	cin >> selection;
	switch (selection){
		case 1:
			temp = newCharacter();
			characters.push_back(temp);
			it = characters.begin();
			while(it != characters.end()){
				(*it)->printStats();
				++it;
			}
			break;
/**********************************************************************/
/* Lots of other code and stuff here, but not important to you.       */
/**********************************************************************/

character * newCharacter(){
	vector<int> stats;
	int temp;
	string name, statNames[9] = {"Void Ring", "Stamina", "Will", "Reflex", 
                        _"Intelligence", "Strength", "Perception", 
                        _"Agility", "Awareness"};
	cout << "Enter the character's:" << endl;
	cout << "Name$ ";
	cin >> name;
	for(int i = 0; i < 9; i++){
		cout << statNames[i] << "$ ";
		cin >> temp;
		stats.push_back(temp);
	}
	character *newChar = new character(name, stats);
	return newChar;
}


The above code actually uses user input to dynamically create a list of different objects all based on the same class. In this way, you don't have to know before you compile exactly how many of each object you will need. The pointers also make polymorphism and inheritance way easier.
One more question:

1
2
3
4
5
6
int x = rand();

Vehicle* AnyVehicle = (x % 2 == 0)
? new Car()
: new Bicycle();


Why does this code give a "Two operands must evaluate to the same type" error? Are a Bicycle* and a Car* not necessarily the same type, then?
No, they are not. Do your random determination separately and then make a new object with an if statement. If nothing else, it should give you insight into what exactly is causing the problem.
Topic archived. No new replies allowed.