Base class array with deried classes

Hello,

I have a problem trying to access functions from the derived classes that are not virtual functions. So in my code I can not use the add(sting s) or setManifest(string s) calls. Am I missing something?

#include <string>
#include <vector>
#include <iostream>
#include "ShippingContainer.h"
#include "ManualShippingContainer.h"
#include "RFIDShippingContainer.h"
using namespace std;

int main()
{
ShippingContainer *ar[6] =
{
new ManualShippingContainer(),
new ManualShippingContainer(),
new ManualShippingContainer(),
new RFIDShippingContainer(),
new RFIDShippingContainer(),
new RFIDShippingContainer()
};

ar[0]->setID(5);
ar[0]->setManifest("Manual Shipping Manifest");

ar[1]->setID(10);
ar[1]->setManifest("Manual Shipping Manifest");

ar[2]->setID(15);
ar[2]->setManifest("Manual Shipping Manifest");

ar[3]->setID(20);
ar[3]->add("crate of apple");
ar[3]->add("crate of apple");
ar[3]->add("crate of apple");
ar[3]->add("crate of apple");
ar[3]->add("crate of oranges");
ar[3]->add("crate of oranges");
ar[3]->add("crate of oranges");
ar[3]->add("crate of bananas");

ar[4]->setID(25);
ar[4]->add("crate of apples");

ar[5]->setID(30);
ar[5]->add("crate of oranges");
ar[5]->add("crate of oranges");
ar[5]->add("crate of apples");

for(int i = 0; i < 5; i++)
{
int temp = ar[i]->getID();
cout << "Container " << temp << " manifest: " << ar[i]->getManifest()
<< ", #" << temp << endl;
}

system("pause");
return 0;

}
Last edited on
I have a problem trying to access functions from the derived classes that are not virtual functions.


If you have a ShippingContainer pointer (as is the case with your 'ar' array), you cannot call functions of ManualShippingContainer. After all, there is no guarantee that the ShippingContainer pointer actually points to a ManualShippingContainer object! Also, there is no way for the compiler to know this is your intent.

To solve this problem, you either need to:

1) design your class hierarchy in a way which virtual functions can be utilized so that you don't have this problem

2) downcast to the derived class, either with dynamic_cast (safe), or with static_cast (not as safe, but quicker).

Example:

1
2
3
4
5
6
7
8
9
10
//  error.. setManifest not a member of ShippingContainer
ar[0]->setManifest("foo");

// ok, but unsafe
static_cast<ManualShippingContainer*>(ar[0])->setManifest("foo");

// okay and safe
ManualShippingContainer* p = dynamic_cast<ManualShippingContainer*>(ar[0]);
if(p)
    p->setManifest("foo");


dynamic_cast does a runtime check to ensure that the cast is legit (ie, the pointer actually points to a ManualShippingContainer object). If the cast is bad, dynamic_cast will return a null pointer.

static_cast does no such runtime check, and if the cast is bad you will call the funciton with a corrupt this pointer which could lead to all kinds of disasterous consequences that are VERY hard to find when debugging. Only use static_cast for downcasting when you are 100% absolutely positive you're casting properly.
For two classes
1
2
3
4
5
6
7
struct A{
	void f();
};

struct B:A{
	void f();
};

If you create a B and assign it to a pointer to A, like this A *p=new B;, p cannot call B::f(), it will always call A::f(). You could override this by casting p to a B *, but that's no very nice. Instead you make A::f() virtual, so that derived classes can override it:
1
2
3
4
5
6
7
struct A{
	virtual void f();
};

struct B:A{
	void f();
};

Now you can do p->f() all you want and it will always call B::f().
Alright. That makes sense. I've been winging this whole program so now at least it runs. Thanks for the help.
Topic archived. No new replies allowed.