Exercise question

Pages: 12
Hi,

I'm trying to make an exercise on polymorphism. I'm not going to ask you to write the code for me, just to give me some clues how to do this.

The exercise (my own words):
You need to store cars in a database, where a vector is used for. There are 5 different sorts of cars (let's say bwm, volvo, etc.). Every car type has it's own properties, but a car in general has some too. So you need to make a general car class and 5 child classes.

When the user starts the program, he can choose to add a car, delete a car, save the database to a text file or load the database from a text file. This is the point where I'm stuck. So I understand I need to create a parent car class, 5 child classes, but how do I need to handle the car adding (remember, they need to be stored in a "database", for which a vector is used)? Do I need to create a new class "database" or something?
Last edited on
Make a vector<car*> database;, then if you want to add a car write database.push_back(new bmw);.
Last edited on
Actually I would make it more of something like:

You need to store vehicles in a database, and there are several different types of vehicles (car, truck, semi, etc). The difference in cars would be more like an std::string make, model, etc or something.

But for the database, hamsterman has it right.
Thank you, I'll have a look what I can do with this =)
Hey,

That seems to work, but why use a pointer here:
vector<car*> database;

It doesn't work without it, but I don't understand why we need one here :(

And how do I access the just added car?
Last edited on
You need one because std::vector needs to know what you want it to contain. If I want a vector of ints I use
std::vector <int> /* blah blah blah */;
if I want a vector of chars:
std::vector <int> /* blah blah blah */;
and so on.

As "car*" is really a pointer to a "car" (I'm assuming this is some class you've created, e.g. class car)... actually I just thought of a really good example as you're using a car.

Think of a car's license (I think in America it's a "registration") plate. It's a number which should be the same on both sides, and should be the car's serial number too (I think).

If you think about it, the registration number is a pointer to the car. Say, for example, your registration/license number was 0x000FFF (lol) then, for example, this:
&myCar would give the memory address (or in the case of our example, registration number) of our car - 0x000FFF.
whereas this:
*myCar would give the value pointed by the registration, and therefore the car itself.
Those operators are the reference operator (&) and the dereference operator (*).

So to access the car, you need the keys (oh god I'm so good at this) and the car's number. As you've got a pointer you know the car's registration number, so you can find it's location in memory. Because you know the location of the car in memory, you can edit it. Bare in mind that you can't edit memory outside of your program's segment (you'll get a "Segmentation fault" or "SIGSEGV" - trying to access memory of another process).

Did that help at all? I think the way I worded my pointers explanation was a little weird. I'm not so good with pointers really myself. I understand them and how to use them... I just rarely ever do except when I want dynamic variables.
Last edited on
Thank you for the explaination, but I'm still stuck :(

I understand what pointers are, what they do and a bit how to use them. But what I still don't get, is why we need a pointer if we want to make a vector of objects.

When we make a vector of ints, we do it this way:
std::vector <int>

Tn this case we don't use a pointer, why not? Why only when working with objects?
Also, do you know the answer on my other question?

Thank you :)
You need to use a pointer there for two possible reasons:
1. You want the vector to be a vector of pointers. A reason I can think of for doing this is something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
int* pInt1 = new int;
int* pInt2 = new int;
// Ugh... I don't want to have to keep on defining integers for dynamic memory...
std::vector <int*> pInts(100, NULL); // Create 100 pointer integers pre-initialized to NULL
// Now we can use pInts like an array of pointers to integers:
for (int i = 0; i < 100; ++i) {
    pInts[i] = new int;
}
// Yeah!
// Do some stuff with pInts...
for (int i = 0; i < 100; ++i) {
    delete pInts[i];
}

2. You want to be able to modify what the vector is pointing to. Unfortunately I can't think of an example...
Last edited on
Hmmm, I think you don't understand me :(

I'm wondering why you NEED to use a pointer, not why you WOULD use a pointer. If you don't use the pointer, the program doesn't compile, so I'm wondering why the pointer is needed.

Also, do you know the answer on this:
And how do I access the just added car?


Thanks again :)
Last edited on
If you take away the asterisk, it doesn't compile? That's weird. What is 'car'? Try declaring it as std::vector <car> HAHNOASTERISK;

Once you've created the vector you can use it sort of like an array.

Say I wanted an array of 1000000 (1 million) elements all initialized to 0. It would take AGES to run this:
1
2
3
4
5
6
7
8
9
10
11
int myArray[1000000];

for (int i = 0; i < 1000000; ++i) {
    myArray[i] = 0;
}

std::cout << "Now that my array has been initialized, I will do stuff with it. HAHAHAHA";

// Blah blah blah sieve of eratosthenes (that's what I used vector for anyway)

std::cout << "Blah blah blah prime numbers blah maths is boring";


So instead, you do this:

1
2
3
4
5
6
std::vector <int> myVector(1000000, 0); // Create a vector of 1,000,000 elements initialized to 0
std::cout << "Now I have a vector of 1 million ints, and it didn't even take ten hours to do!";

// Sieve of boringness

std::cout << "I'm boring";
Hmmm, wait, it actually DOES compile. The push_back line gives an error.

error C2664: 'std::vector<_Ty>::push_back' : cannot convert parameter 1 from 'bmw *' to 'const car &

bmw is a childclass of car. I'm just using inheritance here. The class car has a few data members, the class bmw has some others. Is this a wrong way? Should I use polymorphism here (sorry, I still don't really understand when to use it).

Also, what I mean with my second question:
When you used the push_back function and you want to edit the newly added object in the vector, how to access it? I know you can access it with [0], [1], etc. but how do you know at which index the object is stored?

Thank you
I think it's because bmw might be a pointer to type car, whereas car is a class.

As to your second question:
Well, here's a definition of push_back:
vector::push_back public member function

void push_back ( const T& x );

Add element at the end

Adds a new element at the end of the vector, after its current last element. The content of this new element is initialized to a copy of x.


"Add element at the end".

So it will be this:
1
2
3
4
5
std::vector <int> myVec(100, 1);
int x = sizeof(myVec);
myVec.push_back(500); // Add 500 to a new element
if (x != sizeof(myVec)
    std::cout << "x = " << x << " and sizeof(myVec) = " << sizeof(myVec) << "\n";

sizeof(myVec) after the push_back operation will be 101, so you will know that it is stored at index 100.

Sorry, I just had to laugh at "constant car".
I don't know why.
Last edited on
Ok, I understand the push_back now.

bmw is just a normal childclass. No pointers or constants used :S
I'm not sure, then. Sorry... my object-oriented programming knowledge is severely lacking...
I never bothered learning friendship and inheritance. I always thought they were boring. I'm learning all that stuff now :P
Last edited on
Ok lol.

Here some fast-written code to explain what I'm trying:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class car
{
public:
car();
car(parameter);

protected:
std::string string1;
std::string string2;
int integer1;
};


class bmw : public car
{
public:
bmw()
bmw(parameter);

public: // Normally I make this private ofcourse, but it's easier to make it public for this example.
float number;
char letter;
};


Ofcourse I have my constructors written.

My main file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <string>
#include <vector>
#include "car.h"

using namespace std;

int main()
{
vector<car*> database; // I'm working with dynamic memory, ofcourse the pointer is needed^_^

database.push_back(new bmw());
database[0]->number = 1;

// Here comes some code to delete dynamic memory

return 0;
}


This gives an error on this line:
database[0]->number = 1;
error C2039: 'number' : is not a member of 'car'

I think this gives an error because I'm working at a general car level to store these in a vector, because when I use a bmw vector, it works fine. So I know what I'm doing wrong, but I don't know what the correct way for this is. Can anyone help?

Thank you very much :)
Last edited on
Try declaring "friend bmw;" inside car.

Oh... now I see why car had to be a pointer! It's because you're using the pointer to member operator. It's a dereference operator. That's why it needs a pointer.
If you didn't want to use the arrow operator (->) you could use . instead.
Last edited on
Making it a friend doesn't work :(

But I don't think that's what you need to do, but I really don't understand HOW to do this =(
I thought you would need polymorphism when working with a general car vector, but I don't understand why or how.
Last edited on
Polymorhysm is not ment to be used that way. The idea is that you have a base class that contains some general methods( class car with method Run() - thats what all cars do ), than you subclass it overwritting the methods with other implementations (you subclass the car with Diesel, Petrol and Hybrid and reimplement the Run method - because they dont work the same) and you can still call them with the same method, not caring how they work, but only about the result ( for your example: if you would like to run all cars in the database you'd just call Run() ).

Bv, your example code is ok. Basicly, you need to have all functions that user will be acessing in car. You also put some general stuff there, such as your number, letter. Than, you subclass that car into bmw or ford or whatever. YOu can add new methods and params, but be ware! you will only be able to call those defined in car like you did in the example. You will need to cast it to bmw if you'd like to use it... (but what if the car is an mercedes and has no number? Strange things will occur:P)

I advise you to check the tutorial on this site.
Last edited on
Doesn't that make my bmw-class useless? And as you said, when my car is a mercedes, it doesn't need a number, so that will give trouble.
look @ my edit. Hope it helps.
Pages: 12