I've created a class, called vir, with a function move:
class vir
{
public:
vir(int a,int b,char s){x=a;y=b;sym=s;}
void move(){}
};
(It's derived from a class with variables int x, int y, and char sym)
I have derived a class from this, called subvir:
class subvir:public vir
{
public:
subvir(int a,int b,char s){x=a;y=b;sym=s;}
void move();
};
subvir::move()
{
x++;
return;
}
And then I created an array of vir, and put a subvir into it
subvir sv1(0,0,'Q');
vir vir_RA[1]={sv1};
But when I try to use sv1.move():
vir_RA[0].move();
It uses the vir move ({}) rather than the subvir move ({x++}). I have tried making sv1 a vir and vir_RA a vir, and it works, and it also works when I make them both subvir, but I need them to be different. I tried making vir::move() a pure virtual, but then I get an error substantiating the array. Does anyone know how I can get move() to work when I use it from the array?
You are running into a problem called slicing. Use an array of pointers, or something like Boost.ptr_container.
The base class must have virtual functions to get you what you want, making these pure will result in an abstract base class -- something you cannot instantiate. However, you can still create pointers/references to abstract base classes and assign derived class objects to them. Your base class is best represented as:
class vir
{
public:
vir(int a,int b,char s){x=a;y=b;sym=s;}
virtual void move(){}
};
This makes the derived class's move virtual as well. However your move definition lacks a return value and will not compile. Try:
void subvir::move()
{
x++;
return;
}
Note that you need either pointers (as mentioned in the other answers) or references to derived classes for dynamic binding to work. So, instead of an array of vir objects, use an array of base class pointers:
vir* v[ 2 ] = { new subvir(0, 0, 'Q'), new subvir(10, -10, 'P') };
You should also f
Do read up on the following sections of the C++ FAQ Lite:
Inheritance -- Basics
Inheritance -- Virtual Functions
You need an array of pointers in this case, rather than an array of instances. Use vir*[] instead of vir[]
Two things. The array is an array of vir's so of course it uses the vir::move. move() is not a virtual method.
But more important is slicing. You cannot put subclasses into an array. If sizeof vir != sizeof subvir, the array will not line up correctly. Currently they are the same size. But what happens if they aren't.
Yes, basically compiler does not allow subclasses in arrays because
arrays are initialized tightly for the type size, and subtypes tend
to be larger than the parents and it would lead to problems if you could
initialize arrays with subtype values.
What really happens is compiler first allocates array N * size(base_type) bytes.
And then it copies size(base_type) bytes of each of the initialization
objects. if they were of different types, they would get truncated,
and weird things could happen in your code.
Let me consolidate the previous answers.
There are actually two issues here. One is slicing. You are initializing an array of virs with a copy of a subvir. In such cases the compiler slices the vir part out of the subvir and copies it into the array, so you really do get only vir objects there. Now in your particular case, subvir has no additional data members beyond those of vir, so slicing is somewhat degenerate and the vir object looks a lot like a subvir one. However, vir and subvir are different classes and the object in the array ends up being a vir object and not a subvir object disguised as vir. One way the difference between the two would manifest practically, even if both had the same data members, is if vir had virtual functions overloaded by subvir. In that case the vtable pointer in the object in the array would point to vir's vtable, not subvir's. Of course, it would be even more explicit if subvir were to contain additional data members not found in vir.
The second issue is polymorphism. At the point of usage (the call to move()) the compiler thinks you are calling the move() method of an object of type vir (since the array is an array of virs). (The compiler is of course correct in thinking so due to the slicing, degenerate as it may be in this case.) Had it actually been a subvir object as you intented, you could get subvir::move() called by making move() virtual in vir.
To get the desired behavior you could use an array of pointers (but then you would be operating directly on sv1, not a copy of it, unless you first created a copy and initialized the array with a pointer to the copy).
Related
I was studying Virtual Functions and Pointers. Below code made me to think about, why does one need Virtual Function when we can type cast base class pointer the way we want?
class baseclass {
public:
void show() {
cout << "In Base\n";
}
};
class derivedclass1 : public baseclass {
public:
void show() {
cout << "In Derived 1\n";
}
};
class derivedclass2 : public baseclass {
public:
void show() {
cout << "In Derived 2\n";
}
};
int main(void) {
baseclass * bptr[2];
bptr[0] = new derivedclass1;
bptr[1] = new derivedclass2;
((derivedclass1*) bptr)->show();
((derivedclass2*) bptr)->show();
delete bptr[0];
delete bptr[1];
return 0;
}
Gives same result if we use virtual in base class.
In Derived 1
In Derived 2
Am I missing something?
Your example appears to work, because there is no data, and no virtual methods, and no multiple inheritance. Try adding int value; to derivedclass1, const char *cstr; to derivedclass2, initialize these in corresponding constructors, and add printing these to corresponding show() methods.
You will see how show() will print garbage value (if you cast pointer to derivedclass1 when it is not) or crash (if you cast the pointer to derivedclass2 when class in fact is not of that type), or behave otherwise oddly.
C++ class member functions AKA methods are nothing more than functions, which take one hidden extra argument, this pointer, and they assume that it points to an object of right type. So when you have an object of type derivedclass1, but you cast a pointer to it to type derivedclass2, then what happens without virtual methods is this:
method of derivedclass2 gets called, because well, you explicitly said "this is a pointer to derivedclass2".
the method gets pointer to actual object, this. It thinks it points to actual instance of derivedclass2, which would have certain data members at certain offsets.
if the object actually is a derivedclass1, that memory contains something quite different. So if method thinks there is a char pointer, but in fact there isn't, then accessing the data it points to will probably access illegal address and crash.
If you instead use virtual methods, and have pointer to common base class, then when you call a method, compiler generates code to call the right method. It actually inserts code and data (using a table filled with virtual method pointers, usually called vtable, one per class, and pointer to it, one per object/instance) with which it knows to call the right method. So when ever you call a virtual method, it's not a direct call, but instead the object has extra pointer to the vtable of the real class, which tells what method should really be called for that object.
In summary, type casts are in no way an alternative to virtual methods. And, as a side note, every type cast is a place to ask "Why is this cast here? Is there some fundamental problem with this software, if it needs a cast here?". Legitimate use cases for type casts are quite rare indeed, especially with OOP objects. Also, never use C-style type casts with object pointers, use static_cast and dynamic_cast if you really need to cast.
If you use virtual functions, your code calling the function doesn't need to know about the actual class of the object. You'd just call the function blindly and correct function would be executed. This is the basis of polymorphism.
Type-casting is always risky and can cause run-time errors in large programs.
Your code should be open for extension but closed for modifications.
Hope this helps.
You need virtual functions where you don't know the derived type until run-time (e.g. when it depends on user input).
In your example, you have hard-coded casts to derivedclass2 and derivedclass1. Now what would you do here?
void f(baseclass * bptr)
{
// call the right show() function
}
Perhaps your confusion stems from the fact that you've not yet encountered a situation where virtual functions were actually useful. When you always know exactly at compile-time the concrete type you are operating on, then you don't need virtual functions at all.
Two other problems in your example code:
Use of C-style cast instead of C++-style dynamic_cast (of course, you usually don't need to cast anyway when you use virtual functons for the problem they are designed to solve).
Treating arrays polymorphically. See Item 3 in Scott Meyer's More Effective C++ book ("Never treat arrays polymorphically").
I'm really confused, so I have to ask this. I try to write an application, but I don't know how to reach the variables of the derived class, which are in a vector in the Base class.
The code is:
class A {
public:
A() { };
std::vector<A> aVector;
void Foo();
}
class B : public A {
public:
B() { };
int j;
}
void A::Foo() {
aVector.push_back( B() );
// Here I would like to reach B::j, but only the members and variables of A comes in
aVector[0].j; // wrong
B b = aVector[0]; // no suitable user-defined conversion from "A" to "B" exists
// should I use cast? which one?
}
I'm currently learning inheritance and this kind of things through application programming, and now I'm really stuck.
I looked for other questions, but could not find any that solves my problem. If there is, and I missed, then sorry.
You need to store pointers to A so that your new B object won't get "sliced" (see explanation here) when pushed into the vector.
Also, when you want to use specifically a child method / variable on a pointer from the base class, you need to cast it into the proper type
std::vector<A*> aVector;
aVector.push_back(new B());
B* b = (B*)aVector[0];
cout << b->j;
// remember to delete the content of aVector
Casting an object like this can be dangerous if you are not 100% sure that it is of the type you're casting it in.
See this thread for more information on casting (C style, dynamic_cast and static_cast)
Since the vector is declared to hold objects of type A, when you push a B in to the vector, all the B-ness is stripped away from the object that's stored in the vector. This is known as the slicing problem.
When you later try to access the B elements of the objects stored in the vector you can't because they simply don't exist. You don't have a vector of B objects -- you have a vector of A objects.
In order to solve this problem, you need to store A objects not by value, but by reference or by pointer. You can't store references in a vector, so this leaves you with pointers.
This has nothing to with vectors. If B derives from A then the following code:
A a;
B b = a;
is an error (unless there is some method to convert).
This is correct - your vector items you should be able to handle uniformly. If this means the code that uses the vector expects all items to be B then just make a vector<B>. If not, then you have no business converting an A to a B anyway.
You should never try to access derived class members from the base class. The base class should be agnostic about the implementation details of the derived class. What you are doing is not polymorphic. In other words your B instances cannot act like A instances, because you provided no virtual methods and overrode no virtual methods.
The entire design and approach is incorrect. A::Foo() should be a virtual method (Perhaps even abstract). And you should be doing the work in B::Foo().
And another thing, you shouldn't hold a vector of just plain old A. It should be pointers to A. So std::Vector. And that member should be prefixed with the letter m, to indicate it's a member variable of the class. So std::vector mSomething;
It is usually allowed to do something like that (no comments on the code please :-))
class SimpleClass {
int member;
};
SimpleClass instance;
int* pointer = (int*) &instance;
However, if I define my class as:
class SimpleClass {
virtual void foo();
int member;
};
I can't do that anymore. Well, I guess I can, of course; it's just more complex.
So I was wondering: is it somewhere specified, or the only way to know when I can do that is just to use some common sense? Not counting alignment issues, which can usually be solved
Generally you want to keep the innards of a class of closed off from the outside world as you can, but if you do need to access a member directly simply specify it as public and take a pointer directly to it.
class SimpleClass {
public:
int member;
};
SimpleClass instance;
int* pointer = &instance.member;
I would avoid accessing the members in the way you describe because as you noted small changes in the class can mess it up, which may be fine whilst you are writing the code but when you come back to it much later you will probably overlook such subtleties. Also unless the class is constructed entirely of native data types, I believe the compiler's implementation will affect the required offset as well.
You can only do this safely if your class is plain old data (POD).
From Wikipedia:
A POD type in C++ is defined as either a scalar type or a POD class. A POD class has no user-defined copy assignment operator, no user-defined destructor, and no non-static data members that are not themselves PODs. Moreover, a POD class must be an aggregate, meaning it has no user-declared constructors, no private nor protected non-static data, no base classes and no virtual functions. The standard includes statements about how PODs must behave in C++.
See this page for many details on POD types. In particular,
"A pointer to a POD-struct object, suitably converted using a reinterpret_cast, points to its initial member ... and vice versa" [§9.2, ¶17].
class SimpleClass {
int member;
};
SimpleClass instance;
int* pointer = (int*) &SimpleClass;
In the above code pointer points to SimpleClass::member and hence you can access SimpleClass::member in this way.
Once you add an virtual method to the class SimpleClass, the memory map of the object changes.
class SimpleClass {
virtual void foo();
int member;
};
Every object of SimpleClass now contains a special pointer called as vptr which points to a vtable which is a table of addresses of all virtual functions in SimpleClass. The first 4 bytes of every object of SimpleClass now point to the vptr and not SimpleClass::member and that is the reason you cannot access member in the same way as first case.
Ofcourse, virtual behavior is implementation detail of compilers and vptr nor vtable are specified in the standard but the way i mentioned is how most compilers would implement it.
Since the implementation detail might be different for each compiler you should rely on accessing class members through pointers to class(especially polymorphic classes). Also, doing so defeats the entire purpose of Abstraction through Access Specifiers.
All right, several things.
Your first code example won't compile because you can't have a pointer to a class. I think you meant this:
SimpleClass instance;
int* pointer = (int*) &instance;
(Please don't code you haven't tried compiling.)
This kind of casting is powerful and dangerous. You could just as well cast to a pointer to some type (say, char*) and as long as it was a type no larger than int, the code would compile and run. This kind of reinterpretation is like a fire axe, to be used only when you have no better choice.
As it is, pointer points to the beginning of 'instance', and instance begins with instance.member (like every instance of SimpleClass), so you really can manipulate that member with it. As soon as you add another field to SimpleClass before member, you mess up this scheme.
In your second code example, you can still use pointer to store and retrieve an int, but you're doing so across boundaries within the memory structure of instance, which will damage instance beyond repair. I can't think of a good metaphor for how bad this is.
In answer to your questions: yes, this is specified somewhere, and no, common sense isn't good enough, you'll need insight into how the language works (which comes from playing around with questions like this).
I'm making an application which uses OpenGL and currently store an array of objects that should be rendered each frame which look something like this:
class Object {
private:
float x;
float y;
public:
void func1();
void func2();
...
};
I'd like to be able to create a vertex buffer object from the array of these objects, but I can't simply pass the array since the class contains the additional functions which glBufferData doesn't expect.
Would it be possible to separate the object class like so:
class baseObject {
public:
float x;
float y;
};
class derivedObject : public baseObject {
public:
float x;
float y;
void func1();
void func2();
...
};
and then cast an array of derivedObjects into an array of baseObjects using static_cast or otherwise which can then be passed to glBufferData? Or is the only way to iterate through the array of Objects, extracting the x and y variables into a separate array which can then be passed to glBufferData?
The functions in your class Object don't actually contribute anything to the object's layout. Although the spec doesn't guarantee this, on all major compilers the in-memory representation of an object is just its fields. (If you add a virtual function into the mix, though, this isn't true). In your case, your Object class would look indistinguishable from this struct in memory:
struct JustObjectFields {
float x, y;
};
Because when you remove the member functions, this is what you're left with.
The reason for this is that member functions are typically compiled down to regular functions that take the this pointer as an explicit first argument. This code is separate from any one instance of the class, and so the class size isn't affected by them. In short, you should be able to do this without using inheritance at all. Just use your raw Object class.
You could create an array of base class pointers and manually point them to the elements in the derived class array. However, you cannot do any kind of fancy cast on the array itself because array offsets depend on knowing the actual size of each element. With pointers, this is not a problem, but with actual instances in an array, you'd run into lots of crashing when you try to access individual elements using a pointer of the wrong type.
Typecast for arrays doesn't work in such case - http://codepad.org/6DFLPPDH
In general, its impossible to transform an array of derived objects into
array of base objects without moving the data, and I guess nobody bothered
to support specifically the case where derived class only adds methods.
In fact, even array pointer cast is not very reliable - http://codepad.org/15a4cCy9
But with plain pointers its certainly not a problem - http://codepad.org/4vEK5wY1
And in your case it should be ok anyway, I guess.
Short answer: yes. If glBufferData accepts baseObject as a parameter, then derivedObject may also be used, since an instance of class derivedObject is also an instance of class baseObject.
The issue here isn't methods/functions, but data. glBufferData expects an instance of class baseObject as a parameter because the method requires an object containing exactly the data members described in baseObject. Object is invalid as a parameter because its data members may differ from baseObject. This could prove disastrous if the method is passed an object with invalid data.
However, by defining derivedObject as inheriting from baseObject, we are saying that derivedObject IS a baseObject plus all the data members listed in derivedObject's definition. So, when we pass an instance of derivedObject to glBufferData, it can treat it like an instance of baseObject without danger.
First of all have a look at the following code (in this code shape is the base class and line is the derived class)
void drawshapes(shape sarray[],int size)
{
for(int i=0;i< size; i++)
sarray[i].draw();
}
main()
{
line larray[10];
larray[0]=line(p1,p2);//assuming that we have a point class
larray[1]=line(p2,p3);
..........
drawshapes(larray,10);
}
when we compile this program the draw method of shape would be called at first then program terminates. why it terminates ? why we can not implement polymorphism without base class pointer or reference what is the technical reason for this? what compiler will do if we are trying to implement polymorphism with the array of objects ? please explain in much understandable manner with examples. I will be very thankful.
You are asking a question and providing a code example that fails but for a different reason. From the wording of your question:
Why are references/pointers required for polymorphism?
struct base {
virtual void f();
};
struct derived : public base {
virtual void f();
};
void call1( base b ) {
b.f(); // base::f
}
void call2( base &b ) {
b.f(); // derived::f
}
int main() {
derived d;
call1(d);
call2(d);
}
When you use pass-by-value semantics (or store derived elements in a base container) you are creating copies of type base of the elements of type derived. That is called slicing, as it resembles the fact that you have a derived object and you slice/cut only the base subobject from it. In the example, call1 does not work from the object d in main, but rather with a temporary of type base, and base::f is called.
In the call2 method you are passing a reference to a base object. When the compiler sees call2(d) in main it will create a reference to the base subobject in d and pass it to the function. The function performs the operation on a reference of type base that points to an object of type derived, and will call derived::f. The same happens with pointers, when you get a base * into a derived object, the object is still derived.
Why can I not pass a container of derived pointers to a function taking a container of base pointers?
_Clearly if derived are base, a container of derived is a container of base.
No. Containers of derived are not containers of base. That would break the type system. The simplest example of using a container of derived as container of base objects breaking the type system is below.
void f( std::vector<base*> & v )
{
v.push_back( new base );
v.push_back( new another_derived );
}
int main() {
std::vector<derived*> v;
f( v ); // error!!!
}
If the line marked with error was allowed by the language, then it would allow the application to insert elements that are not of type derived* into the container, and that would mean lots of trouble...
But the question was about containers of value types...
When you have containers of value types, the elements get copied into the container. Inserting an element of type derived into a container of type base will make a copy of the subobject of type base within the derived object. That is the same slicing than above. Besides that being a language restriction, it is there for a good reason, when you have a container of base objects, you have space to hold just base elements. You cannot store bigger objects into the same container. Else the compiler would not even know how much space to reserve for each element (what if we later extend with an even-bigger type?).
In other languages it may seem as this is actually allowed (Java), but it is not. The only change is in the syntax. When you have String array[] in Java you are actually writting the equivalent of string *array[] in C++. All non-primitive types are references in the language, and the fact that you do not add the * in the syntax does not mean that the container holds instances of String, containers hold references into Strings, that are more related to c++ pointers than c++ references.
First: you're mixing two concepts: polymorphism, and value vs. reference semantics.
Runtime polymorphism
Polymorphism comes in many shapes. Depending on the runtime you use, other options are available.
An interpreted language (like Ruby, Python, Javascript, ...) allows for 'duck typing': if an object merely has a method called foo, you can call it. Typically these languages do garbage collection, so the notion of pointers vs. objects isn't too relevant.
C++ has a different viewpoint: polymorphism is allowed, but in a more strict way. Enforcing a common base class (which may be abstract) allows the compiler to check the semantics of your code: this way the compiler assures that you really meant the foo method which implements the intended interface, and not some mishmash of foos.
This polymorphism is realized through the use of a virtual function: a pointer to a function, which may vary amongst implementations. The caller of foo will first have to look up the value of the function pointer, and then jump to that function.
So far for polymorphism.
Containment
Now for containment: if you create an array of line objects in C++, these objects are right next to each other in memory; they're contained by value. When you pass the array to a function, the called function can only receive an array of the same type. Otherwise, taking a step of sizeof(shape) into the array we would end up in the mid of a line.
In order to fix that, you can contain the objects 'by reference' - in C++ we use pointers for that.
Compile-time polymorphism
But there is another way to achieve polymorphic functions: templates. You can write your drawshapes function with a template argument that says which type of object you are using:
template< typename tShape, size_t N >
void drawshapes( tShape (&aShapes)[N] ) {
for( tShape* shape=aShapes; shape != aShapes+N; ++shape ) {
shape->draw();
}
}
(Note: there are stl functions to simplify this, but that's out of the scope of the question.
std::for_each( shapes, shapes+10, mem_fun_ref( &shape::draw ) );
)
You cannot pass an array of line instead of an array of shape.
You must use array of pointers.
This happens because when the function tries to access the second member, it does *(sarray + sizeof(shape)) instead of *(sarray + sizeof(line)), that would be the correct way to access the second element of an array of line.
You want something like this:
void drawshapes(shape *sarray[],int size)
{
for(int i=0;i< size; i++)
sarray[i]->draw();
}
main()
{
shape *larray[10];
larray[0] = new line(p1,p2);//assuming that we have a point class
larray[1] = new line(p2,p3);
..........
drawshapes(larray, 10);
// clean-up memory
...
}