#define classAnum 2;
#define classBnum 3;
class Base
{
virtual int open()=0;
virtual int close()=0;
}
class A:public Base
{
virtual int open();
virtual int close();
};
class B:public Base
{
virtual int open();
virtual int close();
}
int main()
{
A classA[classAnum];
B classB[classBnum];
openAnyClass(1);
CloseAnyClass(2);
}
I want to achieve functionality like this.
openAnyClass(1);
CloseAnyClass(2);
these 2 functions should be able to call open() and close() from any of class A and B.
openAnyClass(1) would call the open() function of 1st object in the array of either classA or classB.
open() --> will have different implementation in class A and class B. and open() in classA may be called from multiple clients and max. no. of clients is # defined.
At a time only one open() from any of the classA or classB is called. I dont want to have several copies of the same code.
with just one function i want call open() of any of class A and any of client.
for Eg: in the below statement i want to call open() of class A of client1. the param to openAnyClass(int) indicates the client Id. This could also meant classB[1].open();
'openAnyClass(1) = classA[1].open();'
What is the best way of doing this?
This is the reason for having a command base class that you derive from; that way you can have a pointer or reference to a class and call the open/close method in the derived classes via the virtual functions.
So if you had
Base *generic_class_pointer = new class A();
generic_class_pointer->open();
The generic_class_pointer->open() would invoke the code defined in class A.
What you're trying to do with two arrays that store objects, one for classes A and one for classes B is not required, you can have a single array that refers to classes of type Base and access via this.
The original code is not really a good way of working, it's better to do this via a list (eg. stl::vector).
Base* class_storage[StorageSize];
int openAnyClass(int id)
{
if (id < 0 || id >= StorageSize || class_storage[id] == 0)
return 0; // or other error indication
else
return class_storage[id]->open();
}
int CloseAnyClass(int id)
{
if (id < 0 || id >= StorageSize || class_storage[id] == 0)
return 0; // or other error indication
else
return class_storage[id]->close();
}
int main()
{
memset(class_storage,0,sizeof(class_storage));
class_storage[1] = new A();
class_storage[2] = new B();
openAnyClass(1);
CloseAnyClass(2);
}
The above code isn't a complete solution, for example the original doesn't have virtual destructors which is a good practice to always use - in case a derived class needs to do cleanup.
Also the deletion of the objects allocated into the class_storage isn't freed on my sample. It doesn't matter at global level because they will be freed upon exit, however most of the time you need to manage everything acquired via new() otherwise you'll get memory leaks.
so classA is an array of A, and same for classB. and calling openAnyClass(1), means call open() on all instances of A, and closeAnyClass() means call close() on all instances of classB. well if this is the case, the question is really complicated formulated
anyways there's no no known out of the box method to do that. you have to iterate on all elements of the array and call open() or close(). alternatively you can use boost foreach
http://www.boost.org/doc/libs/1_39_0/doc/html/foreach.html
or implement your own foreach method
If I understand your question correctly, you want to call different implementations of a pure virtual function. Assuming you have provided implementations of class A and class B, you should be able to make use of polymorphism and call open()/close() from a pointer/reference to a Base instead of A or B.
Instead of creating two arrays for A and B, you can create only one array of Base pointers.
Example:
Base* base[basenum];
void openAnyClass( const int i )
{
if( i < basenum && i >=0 && base[i] != NULL )
base[i]->open();
}
int main(void)
{
base[0] = new A();
base[1] = new B();
...
openAnyClass(1);
closeAnyClass(2);
for( int i = 0 ; i < basenum ; i++ )
delete base[i];
}
As a side note, I think it would be better to make use of open and close functions like these:
void openAnyClass( Base& base );
void closeAnyClass( Base& base );
Rather than using a global variable to store the objects and passing an index, pass the pointer/reference of the object to the function and the function would call the appropriate method(whether the method of A or B).
Related
I have 1 question because I am pretty curious how to handle with such problem.
I have base class called "Pracownik" (Worker) and 2 subclasses which are made from public Pracownik;
- Informatyk (Informatic)
- Księgowy (Accountant)
Writing classes is easy. Made them pretty fast but I have small problem with main because I am helping friend with program but I was not using C++ for a while. So:
This is my header file "funkcje.h"
#include <iostream>
using namespace std;
class Pracownik
{
private:
string nazwisko;
int pensja;
public:
Pracownik(string="",int=0);
~Pracownik();
string getNazwisko();
int getPensja();
friend double srednia_pensja(int,Pracownik);
};
class Informatyk : public Pracownik
{
private:
string certyfikat_Cisco;
string certyfikat_Microsoft;
public:
Informatyk(string="",int=0, string="", string="");
~Informatyk();
void info();
};
class Ksiegowy : public Pracownik
{
private:
bool audytor;
public:
Ksiegowy(string="",int=0, bool=false);
~Ksiegowy();
void info();
};
double srednia_pensja(int,Pracownik);
These are definitions of my functions "funkcje.cpp"
#include "funkcje.h"
Pracownik::Pracownik(string a,int b)
{
nazwisko=a;
pensja=b;
}
Pracownik::~Pracownik()
{
}
string Pracownik::getNazwisko()
{
return nazwisko;
}
int Pracownik::getPensja()
{
return pensja;
}
Informatyk::Informatyk(string a, int b, string c, string d) : Pracownik(a,b)
{
certyfikat_Cisco=c;
certyfikat_Microsoft=d;
}
Informatyk::~Informatyk()
{
}
Ksiegowy::Ksiegowy(string a, int b, bool c) : Pracownik(a,b)
{
audytor=c;
}
Ksiegowy::~Ksiegowy()
{
}
void Informatyk::info()
{
cout<<"Nazwisko pracownika: "<<Pracownik::getNazwisko()<<endl;
cout<<"Pensja pracownika: "<<Pracownik::getPensja()<<endl;
cout<<"Certyfikat Cisco: "<<certyfikat_Cisco<<endl;
cout<<"Certyfikat Microsoft: "<<certyfikat_Microsoft<<endl;
}
void Ksiegowy::info()
{
cout<<"Nazwisko pracownika: "<<Pracownik::getNazwisko()<<endl;
cout<<"Pensja pracownika: "<<Pracownik::getPensja()<<endl;
cout<<"Audytor: ";
if(audytor)
cout<<"Tak"<<endl;
else
cout<<"Nie"<<endl;
}
double srednia_pensja(int a,Pracownik *b)
{
return 0;
}
And finally main!
#include <iostream>
#include "funkcje.h"
using namespace std;
int main()
{
Pracownik lista[10];
Pracownik *lista_wsk = new Pracownik[10];
Informatyk a("Kowalski1",1000,"Cisco1","Microsoft1");
Informatyk b("Kowalski2",2000,"Cisco2","Microsoft2");
Informatyk c("Kowalski3",3000,"Cisco3","Microsoft3");
Ksiegowy d("Kowalski4",4000,1);
Ksiegowy e("Kowalski5",5000,0);
lista[0]=a;
lista[1]=b;
lista[2]=c;
lista[3]=d;
lista[4]=e;
Informatyk *ab = new Informatyk("Kowalski1",1000,"Cisco1","Microsoft1");
Informatyk *ac = new Informatyk("Kowalski2",2000,"Cisco2","Microsoft2");
Informatyk *ad = new Informatyk("Kowalski3",3000,"Cisco3","Microsoft3");
Ksiegowy *ae = new Ksiegowy("Kowalski4",3000,1);
Ksiegowy *af = new Ksiegowy("Kowalski5",3000,0);
lista_wsk[0]=*ab;
lista_wsk[1]=*ac;
lista_wsk[2]=*ad;
lista_wsk[3]=*ae;
lista_wsk[4]=*af;
for(int i;i<5;i++)
{
lista[i].info();
cout<<endl;
}
cout<<endl;
// for(int i;i<5;i++)
// {
// lista_wsk[i].info();
// }
return 0;
}
Ok and here goes my questions:
I had to create array which is filled with base class objects "Pracownik".
Secondary i had to create array which is full of pointers to class "Pracownik" objects.
(Hope those 2 first steps are done correctly)
Next thing I had to write to array 3 objects of class Informatic and 2 of class Accountant.
So I ve created 5 objects manually and added them into the array in such way array[0]=a;. I guess this is still good.
Next thing i had to create and add similar objects to array of pointers using new. So I ve created array with new and pointers to objects with new. (Hope thats correct 2).
And FINALLY:
I had to use info() on added to array objects.
This is my main question if my array is type "Pracownik" and I want to use function info() from subclasses how should I do that? And how compiler will know if he should use info() from Accountant or Informatic while I am trying to show those information using "for".
In an array of Pracownik, the elements are of type Pracownik. Any information about the objects being of a subclass of Pracownik are lost when you copy the elements into the array.
This is called object slicing and leads to the fact that there is no way to invoke Informatyk::info() on these objects.
If you want to call methods of a subclass, you have to prevent object slicing by storing pointers or references in the array.
As Oswald says in his answer,
Pracownik * lista_wsk = new Pracownik[10];
allocates an array of 10 Pracownik objects. This is probably not what you want. With polymorphism involved, we usually want to deal with pointers or references. Hence, you'd want an array of Pracownik * pointers. Since you already know at compile-time that it will have 10 members, there is no need for a dynamic allocation here. I think you've meant to write
Pracownik * lista_wsk[10];
instead. Now we don't put objects but pointers to objects into the array. For example:
lista_wsk[2] = new Informatyk("Kowalski3", 3000, "Cisco3", "Microsoft3");
And then we can iterate over the items like so:
for (unsigned i = 0; i < 10; ++i)
std::cout << lista_wsk[i]->getNazwisko() << std::endl;
As you have already discovered, it is impossible to call a subclass function member on a superclass object. It would be possible to figure out the actual type at run-time yourslf by means of a cast.
for (unsigned i = 0; i < 10; ++i)
if (Informatyk * info_ptr = dynamic_cast<Informatyk *>(lista_wsk[i]))
info_ptr->info();
dynamic_cast returns a pointer to the target class if this is possible or a nullptr (which evaluates to false, hence the conditional) otherwise. Note however that this is considered very poor style. It is better to use virtual functions. Therefore, add
virtual void
info()
{
// Do what is appropriate to do for a plain Pracownik.
// Maybe leave this function empty.
}
to the superclass and again to the subclass
virtual void
info() // override
{
// Do what is appropriate to do for an Informatyk.
}
The function in the subclass with the same signature is said to override the function inherited from the superclass. Since the function is marked as virtual, the compiler will generate additional code to figure out at run-time what version of the function to call.
If you are coding C++11, you can make the override explicit by placing the keyword override after its type as shown above (uncomment the override). I recommend you use this to avoid bugs that arise from accidental misspelling or other typos.
I have a problem I am working on. I have a number classes which inherit each other in this pattern:
#include <stdio.h>
#include <stdlib.h>
#include <list>
class TimeObject
{
public:
virtual void Tick()=0;
std::list<TimeObject*> ticks;
};
class MapObject : public TimeObject
{
public:
MapObject()
{
ticks.push_front(this);
printf("Create MapObject %p\n", this);
}
void Tick() { printf("mapobject tick\n"); }
};
class ControlObject : public MapObject
{
public:
ControlObject()
{
ticks.push_front(this);
printf("Create ControlObject %p\n", this);
}
void Tick() { printf("controlobject tick\n"); }
};
int main()
{
ControlObject test;
std::list<TimeObject*>::iterator it = test.ticks.begin();
for(; it != test.ticks.end(); it++)
{
TimeObject *trigger = *it;
trigger->Tick();
}
return 0;
}
The list in the example stores any TimeObject derived class. My problem is that when storing MapObject pointers in the list that are also ControlObjects dispatch always picks the ControlObject function.
Is it possible to trigger the MapObject function with a ControlObject pointer using polymorphism? If it isn't possible/pratical, what would be a good alternative?
You should always store pointer to the Base class A* in the list(std::list< A*>).
The pointer should be correctly made to point either a object of type Bor C before you add the pointer to the container.
Once you do that, dynamic dispatch will take care of calling the correct function for you depending on the actual object type. You don't need to do anything.
I don't know why you want to have any design which is otherwise, If you have any good reasons to do so please let know of them.
Why it always calls ControlObject::tick() in your code?
When you call:
ticks.push_front(this);
in ControlObject::ControlObject() you basically end up overwriting the first pointer you added to the list, The type of the first pushed pointer is not MapObject * anymore it is ControlObject * because you changed the pointer behind its back.You did not transfer ownership of the pointer to the list but you both had shared ownership and you modified the object in your list through the constructor call in derived class. This leaves you with two ControlObject * objects in the list which dynamic dispatch correctly determines and calls the correct method.
There is nothing wrong in what dynamic dispatch does, it is the correct behavior.
If you want to call MapObject::Tick(); then you will explicitly have to tell the compiler to do so, dynamic dispatch works on the actual type of object and it is working correctly.
void controlobject::Tick()
{
printf("controlobject tick\n");
MapObject::Tick();
}
Replicating from the comments:
I am afraid this is a bad design.The code works as it should,it works as defined by the C++ standard.The problem lies in the design.And unless you provide the details of what you are trying to achieve in a broader sense it is difficult and rather pointless to speculate on a new design.
Using a cast on the variable of type C to the type B should do the trick.
C c;
B b;
c.Function();
((B)c).Function();
A * l[] = {&c,&b,&c};
l[0]->Function();
l[1]->Function();
l[2]->Function();
B test = *(B*)l[0];
test.Function();
In your current example you should be able to call both virtual members (or just the one depending on the underlying type) by calling MapObject::Tick() inside ControlObject::Tick():
class ControlObject : public MapObject
{
public:
ControlObject()
{
ticks.push_front(this);
printf("Create ControlObject %p\n", this);
}
void Tick() { printf("controlobject tick\n"); MapObject::Tick(); }
};
The explicit function call notation is required.
I have a variable, which is a member of one of my classes, that another is in need of, but I'm not sure how to effectively pass the value between them without using a global variable, which is something I'd like to avoid if at all possible. I know I could create an object, but that would invoke the constructor of the originating class which would execute a number of functions and write the needless results to memory, which would be wasteful of system resources.
Is there an easy way to pass this value between the two functions?
Update: The class that is in need of the variable, called no_of_existing_devices. The purpose of class Initialise is to open up a file and count the number of lines of test it contains, and place that number in the variable int no_of_existing_devices, which is then used by the Device::Device() to create an object for each
class Device
{
public:
void view_attribute_list();
void set_attribute();
Device();
};
Device::Device()
{
for (int count = 0; count < no_of_existing_devices; count ++)
{
// Create an object for each iteration, up to a maximum of no_of_existing_devices
}
}
The class of which this variable is a member
class Initialise
{
public:
int no_of_existing_devices;
bool initialisation;
string existing_device_list[100];
void initialise_existing_devices();
Initialise();
};
Initialise::Initialise()
{
no_of_existing_devices = 0;
}
void Initialise::initialise_existing_devices()
{
string line;
ifstream DeviceList;
DeviceList.open("devices/device_list");
while (true)
{
getline(DeviceList, line, '\n');
if (DeviceList.eof())
{
break;
}
++ no_of_existing_devices;
}
DeviceList.close();
DeviceList.open("devices/device_list");
for (int i = 0; i < no_of_existing_devices; i ++)
{
getline(DeviceList, line, '\n');
existing_device_list[i] = line;
}
Device existing_devices[no_of_existing_devices];
!initialisation; // Existing devices are now initialised
}
Okay, from what I understand:
You don't want to have a global
You don't want to have a static
You don't want to introduce a dependency between Device and Initialise
There is one other option, assuming something owns Device and Initialise, move the no_of_existing_devices up to there, then construct both Device and Initialise with a reference to this variable...
In a similar circumstance I was just passing the pointer to the member --- I had to invoke a member function then, so it was a pointer to the member function, http://www.parashift.com/c++-faq-lite/pointers-to-members.html
It's a bit messy, but it works :-).
If the variable in the originating class can hold a value without an instance of the class I would assume that the variable is static. If not create a public static member of the class. And use it in the target class.
Something like:
// .h file
class A
{
public:
static int a;
}
// .cpp file
int A::a = 123;
// .cpp file of class B
void B::foo()
{
cout << A::a;
}
If it is a class attribute (internal variable), then you can obtain a reference through a get method. Otherwise, you can use the friend keyword on the class you want to access the attribtue from the other For example, if you declare friend class B; on class A, the attributes of the class B will be accessible on the class A.
I suggest you use the first method in order to maintain your code OO pure ;)
Edit: of course, if you access through a reference there are no resources wasted :)
Edit 2: use a static method on Initialise class that returns the no_of_existing_devices and call Initialise::NoOfExistingDevices() on the Device class. If you want to resources use a pointer like this:
public static int* Initialise::NoOfExistingDevices() {
return &no_of_existing_devices;
}
By the way, I advise you to turn the variable private.
Using C++ I built a Class that has many setter functions, as well as various functions that may be called in a row during runtime.
So I end up with code that looks like:
A* a = new A();
a->setA();
a->setB();
a->setC();
...
a->doA();
a->doB();
Not, that this is bad, but I don't like typing "a->" over and over again.
So I rewrote my class definitions to look like:
class A{
public:
A();
virtual ~A();
A* setA();
A* setB();
A* setC();
A* doA();
A* doB();
// other functions
private:
// vars
};
So then I could init my class like: (method 1)
A* a = new A();
a->setA()->setB()->setC();
...
a->doA()->doB();
(which I prefer as it is easier to write)
To give a more precise implementation of this you can see my SDL Sprite C++ Class I wrote at http://ken-soft.com/?p=234
Everything seems to work just fine. However, I would be interested in any feedback to this approach.
I have noticed One problem. If i init My class like: (method 2)
A a = A();
a.setA()->setB()->setC();
...
a.doA()->doB();
Then I have various memory issues and sometimes things don't work as they should (You can see this by changing how i init all Sprite objects in main.cpp of my Sprite Demo).
Is that normal? Or should the behavior be the same?
Edit the setters are primarily to make my life easier in initialization. My main question is way method 1 and method 2 behave different for me?
Edit: Here's an example getter and setter:
Sprite* Sprite::setSpeed(int i) {
speed = i;
return this;
}
int Sprite::getSpeed() {
return speed;
}
One note unrelated to your question, the statement A a = A(); probably isn't doing what you expect. In C++, objects aren't reference types that default to null, so this statement is almost never correct. You probably want just A a;
A a creates a new instance of A, but the = A() part invokes A's copy constructor with a temporary default constructed A. If you had done just A a; it would have just created a new instance of A using the default constructor.
If you don't explicitly implement your own copy constructor for a class, the compiler will create one for you. The compiler created copy constructor will just make a carbon copy of the other object's data; this means that if you have any pointers, it won't copy the data pointed to.
So, essentially, that line is creating a new instance of A, then constructing another temporary instance of A with the default constructor, then copying the temporary A to the new A, then destructing the temporary A. If the temporary A is acquiring resources in it's constructor and de-allocating them in it's destructor, you could run into issues where your object is trying to use data that has already been deallocated, which is undefined behavior.
Take this code for example:
struct A {
A() {
myData = new int;
std::cout << "Allocated int at " << myData << std::endl;
}
~A() {
delete myData;
std::cout << "Deallocated int at " << myData << std::endl;
}
int* myData;
};
A a = A();
cout << "a.myData points to " << a.myData << std::endl;
The output will look something like:
Allocated int at 0x9FB7128
Deallocated int at 0x9FB7128
a.myData points to 0x9FB7128
As you can see, a.myData is pointing to an address that has already been deallocated. If you attempt to use the data it points to, you could be accessing completely invalid data, or even the data of some other object that took it's place in memory. And then once your a goes out of scope, it will attempt to delete the data a second time, which will cause more problems.
What you have implemented there is called fluent interface. I have mostly encountered them in scripting languages, but there is no reason you can't use in C++.
If you really, really hate calling lots of set functions, one after the other, then you may enjoy the following code, For most people, this is way overkill for the 'problem' solved.
This code demonstrates how to create a set function that can accept set classes of any number in any order.
#include "stdafx.h"
#include <stdarg.h>
// Base class for all setter classes
class cSetterBase
{
public:
// the type of setter
int myType;
// a union capable of storing any kind of data that will be required
union data_t {
int i;
float f;
double d;
} myValue;
cSetterBase( int t ) : myType( t ) {}
};
// Base class for float valued setter functions
class cSetterFloatBase : public cSetterBase
{
public:
cSetterFloatBase( int t, float v ) :
cSetterBase( t )
{ myValue.f = v; }
};
// A couple of sample setter classes with float values
class cSetterA : public cSetterFloatBase
{
public:
cSetterA( float v ) :
cSetterFloatBase( 1, v )
{}
};
// A couple of sample setter classes with float values
class cSetterB : public cSetterFloatBase
{
public:
cSetterB( float v ) :
cSetterFloatBase( 2, v )
{}
};
// this is the class that actually does something useful
class cUseful
{
public:
// set attributes using any number of setter classes of any kind
void Set( int count, ... );
// the attributes to be set
float A, B;
};
// set attributes using any setter classes
void cUseful::Set( int count, ... )
{
va_list vl;
va_start( vl, count );
for( int kv=0; kv < count; kv++ ) {
cSetterBase s = va_arg( vl, cSetterBase );
cSetterBase * ps = &s;
switch( ps->myType ) {
case 1:
A = ((cSetterA*)ps)->myValue.f; break;
case 2:
B = ((cSetterB*)ps)->myValue.f; break;
}
}
va_end(vl);
}
int _tmain(int argc, _TCHAR* argv[])
{
cUseful U;
U.Set( 2, cSetterB( 47.5 ), cSetterA( 23 ) );
printf("A = %f B = %f\n",U.A, U.B );
return 0;
}
You may consider the ConstrOpt paradigm. I first heard about this when reading the XML-RPC C/C++ lib documentation here: http://xmlrpc-c.sourceforge.net/doc/libxmlrpc++.html#constropt
Basically the idea is similar to yours, but the "ConstrOpt" paradigm uses a subclass of the one you want to instantiate. This subclass is then instantiated on the stack with default options and then the relevant parameters are set with the "reference-chain" in the same way as you do.
The constructor of the real class then uses the constrOpt class as the only constructor parameter.
This is not the most efficient solution, but can help to get a clear and safe API design.
When I allocate a single object, this code works fine. When I try to add array syntax, it segfaults. Why is this? My goal here is to hide from the outside world the fact that class c is using b objects internally. I have posted the program to codepad for you to play with.
#include <iostream>
using namespace std;
// file 1
class a
{
public:
virtual void m() { }
virtual ~a() { }
};
// file 2
class b : public a
{
int x;
public:
void m() { cout << "b!\n"; }
};
// file 3
class c : public a
{
a *s;
public:
// PROBLEMATIC SECTION
c() { s = new b[10]; } // s = new b;
void m() { for(int i = 0; i < 10; i++) s[i].m(); } // s->m();
~c() { delete[] s; } // delete s;
// END PROBLEMATIC SECTION
};
// file 4
int main(void)
{
c o;
o.m();
return 0;
}
Creating an array of 10 b's with new and then assigning its address to an a* is just asking for trouble.
Do not treat arrays polymorphically.
For more information see ARR39-CPP. Do not treat arrays polymorphically, at section 06. Arrays and the STL (ARR) of the CERT C++ Secure Coding Standard.
One problem is that the expression s[i] uses pointer arithmetic to compute the address of the desired object. Since s is defined as pointer to a, the result is correct for an array of as and incorrect for an array of bs. The dynamic binding provided by inheritance only works for methods, nothing else (e.g., no virtual data members, no virtual sizeof). Thus when calling the method s[i].m() the this pointer gets set to what would be the ith a object in the array. But since in actuality the array is one of bs, it ends up (sometimes) pointing to somewhere in the middle of an object and you get a segfault (probably when the program tries to access the object's vtable). You might be able to rectify the problem by virtualizing and overloading operator[](). (I Didn't think it through to see if it will actually work, though.)
Another problem is the delete in the destructor, for similar reasons. You might be able to virtualize and overload it too. (Again, just a random idea that popped into my head. Might not work.)
Of course, casting (as suggested by others) will work too.
You have an array of type "b" not of type "a" and you are assigning it to a pointer of type a. Polymorphism doesn't transfer to dynamic arrays.
a* s
to a
b* s
and you will see this start working.
Only not-yet-bound pointers can be treated polymorphically. Think about it
a* s = new B(); // works
//a* is a holder for an address
a* s = new B[10]
//a* is a holder for an address
//at that address are a contiguos block of 10 B objects like so
// [B0][B2]...[B10] (memory layout)
when you iterate over the array using s, think about what is used
s[i]
//s[i] uses the ith B object from memory. Its of type B. It has no polymorphism.
// Thats why you use the . notation to call m() not the -> notation
before you converted to an array you just had
a* s = new B();
s->m();
s here is just an address, its not a static object like s[i]. Just the address s can still be dynamically bound. What is at s? Who knows? Something at an address s.
See Ari's great answer below for more information about why this also doesn't make sense in terms of how C style arrays are layed out.
Each instance of B contains Both X data member and the "vptr" (pointer to the virtual table).
Each instance of A contain only the "vptr"
Thus , sizeof(a) != sizeof(b).
Now when you do this thing : "S = new b[10]" you lay on the memory 10 instances of b in a raw , S (which has the type of a*) is getting the beginning that raw of data.
in C::m() method , you tell the compiler to iterate over an array of "a" (because s has the type of a*) , BUT , s is actualy pointing to an array of "b". So when you call s[i] what the compiler actualy do is "s + i * sizeof(a)" , the compiler jumps in units of "a" instead of units of "b" and since a and b doesn't have the same size , you get a lot of mambojumbo.
I have figured out a workaround based on your answers. It allows me to hide the implementation specifics using a layer of indirection. It also allows me to mix and match objects in my array. Thanks!
#include <iostream>
using namespace std;
// file 1
class a
{
public:
virtual void m() { }
virtual ~a() { }
};
// file 2
class b : public a
{
int x;
public:
void m() { cout << "b!\n"; }
};
// file 3
class c : public a
{
a **s;
public:
// PROBLEMATIC SECTION
c() { s = new a* [10]; for(int i = 0; i < 10; i++) s[i] = new b(); }
void m() { for(int i = 0; i < 10; i++) s[i]->m(); }
~c() { for(int i = 0; i < 10; i++) delete s[i]; delete[] s; }
// END PROBLEMATIC SECTION
};
// file 4
int main(void)
{
c o;
o.m();
return 0;
}