About conversion between pointers - c++

What does actually "conversion between pointers" mean ? If I have something like type_1* x, type_2* y and call dynamic_cast<type_1*>(y) (the question is not about dynamic cast, I used it because it is a function that works well with pointers casting as far as I know) what will it return ? A pointer of type *type_1 that points to the same object as y (or NULL, of course) ? Is this true? Is there anything more I should know to understand these castings between pointers ?

In case of classes and multiple inheritance, casting pointers can change the value (address) of the pointer as well.
Observe:
#include <iostream>
class Foo {
int foo;
};
class Bar {
double bar;
};
class Baz: public Foo, public Bar {
short baz;
};
int main() {
Baz bz;
std::cout << &bz << " " << static_cast<Bar *>(&bz) << " " << static_cast<Foo *>(&bz) << std::endl;
}
That's because the instances of the parent types are at different offsets of the derived object, they can't both sit at the same address.
This is upcasting (child to parent) which is always legal and static_cast is enough, for downcasting (parent to child) the extra checking of dynamic_cast is needed.

What does actually "conversion between pointers" mean ?
It means a conversion from pointer of one type to another pointer type.
what will [dynamic_cast<type_1*>(y)] return ? A pointer of type *type_1 that points to the same object as y (or NULL, of course) ? Is this true?
That is true. The "same object" is correct in an Object Oriented sense. Although from strict C++ sense, the pointed objects of different types may be considered to be different objects.
Is there anything more I should know to understand these castings between pointers ?
Yes, this is not the full extent of the rules relating to pointers and conversions. I recommend reading the documentation thoroughly and possibly some C++ books, in order to understand pointers and conversions.

Some time ago I saw the code that controlled the first Apollo mission. It was all-assembly, the C, lat alone C++, did not exist at those days. We can imagine that in that assembly, all they had at their disposal was registers and raw memory that had to be managed manually.
In modern, non-assembly languages, including C/C++, the compiler frees you from the burden of manual memory management. The memory for named variables, like in
int x = 0;
is allocated and deallocated automatically. Also, you don't need to bother about memory that is needed temporarily, e.g., during some complex computations. In C/C++ these "usual" variables are accompanied by pointers that allow you to access this automatically or semi-automatically managed memory indirectly. Moreover, you need pointers to access the heap-allocated ("nameless") memory (remember operator new?). And this is almost all you should know about them. The syntax is known: the asterisk *, the "arrow" -> and the ampersand &. It's the compiler's duty to protect you from doing probably stupid operation on pointers, like using them as if they are just integers (a popular trick in 1970s) or using them as if they pointed to something else that you've declared. Declaring a pointer means that you declare the whole set of operations on it. To protect you from accidental shooting your foot off, the compiler forbids such horrible things like automatic assignments of pointers of different types.
However, you are the master of the compiler, not the opposite, so you can take the full control. This is where pointer conversion steps in. On the one hand, by ussing pointer conversion, you can temporarily switch off all the safeties the creators of the compiler has prepared for you. On the other hand, with a suitable cast, you can guarantee that your program is correct!
The really important question is: which operations involving pointer conversions are guaranteed to be safe?
The first, a bit surprising thing is: there are several types of pointers, which need not be mutually compatible:
pointer to data
pointer to (free) function
pointer to data member
pointer to member function
void* pointer
Their internal representation, or even the number of bits they occupy, need not be the same!
So, what is allowed?
The C language loves to use void* as the means of passing data of arbitrary type. So you can be sure that you can convert any data pointer to void* and then back to its original type and this will work. Similarly with pointers to functions.
Another place where pointer conversions are natural is low-level serialization. Many function in both C and C++ work on buffers declared as char* or const char*. From this you can infer that you should be able to convert any pointer to data to char* and it will work as expected.
The third common pointer conversion is when you deal with inheritance, especially in the context of classes with virtual functions. Here comes dynamic_cast to cast a pointer in the potentially "dangerous" way along the inheritance tree.
There are also other casts that are safe and others that may lead to undefined behavior or even segmentation fault. For example, pointers to int are often casts to or from pointers to float and it usually works, e.g., in AVX or GPU programming. Correctness of these particular casts are guaranteed by hardware vendors rather than the C++ standard.
What dangers are there if you leave the land of safe casts? For example, you cast a pointer to function to void* and then this pointer to char*. If you try to dereference this pointer, let alone write through it, your program is doomed to die immediately. Similarly dangerous conversions are between pointers to data and pointers to members. Don't do that. Also, don't use pointers to cast pointers to integers etc. This is generally the land of undefined behavior, unless you carefully consulted the standard and are sure the thing you're doing is safe.
To sum this long story up: pointer conversion usually generates no code, but sometimes it does. See the examples below.
EXAMPLES
1. Inheritance. Static cast vs. dynamic cast.
Suppose we have XY derived from both X and Y:
struct X
{
float x;
};
struct Y
{
float y;
};
struct XY : public X, public Y
{
float xy;
};
Then this code:
XY a;
std::cout << static_cast<X*>(&a) << "\n";
std::cout << static_cast<Y*>(&a) << "\n";
std::cout << reinterpret_cast<X*>(&a) << "\n";
std::cout << reinterpret_cast<Y*>(&a) << "\n";
std::cout << &a << "\n";
may produce these results:
0x7fffc7d75dcc
0x7fffc7d75dd0
0x7fffc7d75dcc
0x7fffc7d75dcc
0x7fffc7d75dcc
So, static_cast does change the "value" of the pointer! At the same time, reinterpret_cast only "reinterprets" the bits stored in a pointer variable / register, but does not modify them.
Interestingly, if we defined a virtual method in Y, the same code would reveal a reversed order of X and Y inside XY:
0x7ffc6a45764c
0x7ffc6a457640
0x7ffc6a457640
0x7ffc6a457640
0x7ffc6a457640
So, the order of embedding the base classes in multiple inheritance seems to be undefined / implementation-dependent.
2. casts to integer types
The standard allows to cast pointers to and from integer types of sufficient length.
Casts of "C-style pointers" to integer types work as expected:
XY a;
std::cout << std::hex << reinterpret_cast<uint64_t>(&a) << "\n";
std::cout << reinterpret_cast<void*>(&a) << "\n";
yields, for example,
7fff84f5a6cc
0x7fff84f5a6cc
as expected. But he standard does not guarantee this.
3. pointers to data members
This case is more interesting: pointers to members cannot be cast to anything. But there's a workaround:
XY a;
float XY::* mptr_xy = &XY::xy;
float XY::* mptr_x = &XY::x;
float XY::* mptr_y = &XY::y;
std::cout << *reinterpret_cast<uint64_t*>(&mptr_x) << "\n";
std::cout << *reinterpret_cast<uint64_t*>(&mptr_y) << "\n";
std::cout << *reinterpret_cast<uint64_t*>(&mptr_xy) << "\n";
This may give the following result:
0
4
8
This shows that the pointers to members are offsets into objects memory rather than pointers to RAM. If we add a virtual destructor to Y we may get this:
12
8
16
The offsets have changed, making room for vptr and moving Y to the front. If both X and Y have virtual destructors, a possible result is this:
8
24
28
Conclusion: pointers to members are completely different beasts than standard pointers.
4. Dynamic casts
Suppose both X and Y have virtual destructors. This code:
XY xy;
Y y;
std::cout << "xy:\n";
std::cout << &xy << "\n";
std::cout << dynamic_cast<Y*>(&xy) << "\n";
std::cout << dynamic_cast<Y*>(dynamic_cast<X*>(&xy)) << "\n";
std::cout << dynamic_cast<X*>(&xy) << "\n";
std::cout << "y:\n";
std::cout << &y << "\n";
std::cout << dynamic_cast<XY*>(&y) << "\n";
std::cout << dynamic_cast<Y*>(dynamic_cast<XY*>(&y)) << "\n";
std::cout << dynamic_cast<Y*>(reinterpret_cast<XY*>(&y)) << "\n";
std::cout << dynamic_cast<Y*>(static_cast<XY*>(&y)) << "\n";
may produce this output:
xy:
0x7ffc0a570590
0x7ffc0a5705a0
0x7ffc0a5705a0
0x7ffc0a570590
y:
0x7ffc0a570580
0
0
0x7ffc0a570590
0x7ffc0a570580
Casts of the address of xy may give 2 different results.
Casts of the address of y may give 3 different results.
Summary:
Pointer casts in C++ are far more complex than in C. The standard only guarantees behavior, but not the implementation. So, for example, a cast to an integer type might involve some bit manipulation - existing implementations don't do this because there's no point in doing this, not because it's forbidden. The main differences arise from C++ having multiple inheritance, virtual function and pointers to members.
Caveat. This long reply did not cover all aspects of pointer casts, most notably data alignment. Also, the standard does not impose any limitation on the implementation of various pointers, and even the reinterpret_cast is not guaranteed to preserve the internal bit representation:
Unlike static_cast, but like const_cast, the reinterpret_cast expression does not compile to any CPU instructions (except when converting between integers and pointers or on obscure architectures where pointer representation depends on its type).
https://en.cppreference.com/w/cpp/language/reinterpret_cast
See also:
https://en.cppreference.com/w/cpp/language/explicit_cast
https://en.cppreference.com/w/cpp/language/const_cast
https://en.cppreference.com/w/cpp/language/dynamic_cast
https://en.cppreference.com/w/cpp/language/static_cast
https://en.cppreference.com/w/cpp/language/implicit_conversion

what does casting between pointers mean ?
You change the meaning of the same data / object.
Example 1:
class Base {
public:
void food() {printf("foo\n");}
}
class Derived : public Base {
public:
void bar() {printf("bar");}
}
int main() {
Base * base = new Derived();
base->foo(); // OK, it compiles
base->bar(); // **NOK, syntax error**, even if you instantiated Derived class
Derived * derived = static_cast<Derived *>(base);
derived->foo(); // OK, it compiles
derived->bar(); // OK, it compiles
return 0;
}
Example 2:
int main() {
char word[] = {'W', 'o', 'r', 'd', '\0', '\0', '\0', '\0'}; // array of 8 chars
const char * ptrChar = static_cast<const char *>(word); // cast to "const char* "
const int * ptrInt = reinterpret_cast<const int *>(word); // cast to "const int* "
int lenChar = 0
while (ptrChar[lenChar] != 0)
++ lenChar;
printf("lenChar = %d\n", lenChar); // lenChar = 4
int lenInt = 0;
while (ptrInt[lenInt] != 0)
++ lenInt;
printf("lenInt = %d\n", lenInt); // lenInt = 1
return 0;
}
etc....
You should "play" more with pointers then you'll understand more about pointers and sense of conversion. It is a huge topic and essential in C/C++
dynamic casting is more complex. It requires understanding of run-time and compile-time, polymorphism, hierarchy, etc. In these 2 examples i didn't use dynamic casting because it would not work.

Related

Passing smart pointer to function through non smart pointer argument

Consider the following function:
void example(void **ptr){
std::cout << *ptr << "\n"; // pointer value
std::cout << ptr << "\n"; // pointer address
std::cout << **reinterpret_cast<int**>(ptr); // value
}
The function signature cannot be changed.
Is the following code valid, or should I use raw pointers?
int main()
{
std::unique_ptr<int> x = std::make_unique<int>(20);
std::cout << x.get() << "\n"; // pointer value
std::cout << &x << "\n"; // pointer address
example(reinterpret_cast<void**>(&x));
}
Live sample
It is not valid and has undefined behaviour.
(If it appears to work, it's because your particular implementation happens to store the unique_ptr's underlying pointer as its first member in this particular situation. It is still 100% pure crystal-clear undefined behaviour, though.)
If you can't change the function, you need to pass it something that actually is an int** - &x is a std::unique_ptr<int>*, and no amount of casting can make a valid int** from it.
(I have found that it's often a mistake to think of the smart "pointers" as pointers.)
The way to get a pointer to the underlying object in a smart "pointer" is through get():
int* p = x.get();
and then you can pass a pointer to p (you still need to cast it, though):
example(reinterpret_cast<void**>(&p));
Generally only void * have special rights and privileges when it comes to playing funny games with casting. However, given the situation that you have to work with:
example(reinterpret_cast<void**>(&x));
Note that you're passing &x and laundering it with reinterpret_cast. In example() you should do exactly the opposite:
void example(void **ptr)
{
auto x_ptr = reinterpret_cast<std::unique_ptr<int> *>(ptr);
Now you have a std::unique_ptr<int> * to work with. You can proceed according to your original plans. If you wish, your next step can be:
auto &x=*xptr;
And this x is the same x as in your main, for all practical purposes (and it is).

A function to return different derived-type object/reference not a pointer [duplicate]

I did find some questions already on StackOverflow with similar title, but when I read the answers, they were focusing on different parts of the question, which were really specific (e.g. STL/containers).
Could someone please show me, why you must use pointers/references for implementing polymorphism? I can understand pointers may help, but surely references only differentiate between pass-by-value and pass-by-reference?
Surely so long as you allocate memory on the heap, so that you can have dynamic binding, then this would have been enough. Obviously not.
"Surely so long as you allocate memory on the heap" - where the memory is allocated has nothing to do with it. It's all about the semantics. Take, for instance:
Derived d;
Base* b = &d;
d is on the stack (automatic memory), but polymorphism will still work on b.
If you don't have a base class pointer or reference to a derived class, polymorphism doesn't work because you no longer have a derived class. Take
Base c = Derived();
The c object isn't a Derived, but a Base, because of slicing. So, technically, polymorphism still works, it's just that you no longer have a Derived object to talk about.
Now take
Base* c = new Derived();
c just points to some place in memory, and you don't really care whether that's actually a Base or a Derived, but the call to a virtual method will be resolved dynamically.
In C++, an object always has a fixed type and size known at compile-time and (if it can and does have its address taken) always exists at a fixed address for the duration of its lifetime. These are features inherited from C which help make both languages suitable for low-level systems programming. (All of this is subject to the as-if, rule, though: a conforming compiler is free to do whatever it pleases with code as long as it can be proven to have no detectable effect on any behavior of a conforming program that is guaranteed by the standard.)
A virtual function in C++ is defined (more or less, no need for extreme language lawyering) as executing based on the run-time type of an object; when called directly on an object this will always be the compile-time type of the object, so there is no polymorphism when a virtual function is called this way.
Note that this didn't necessarily have to be the case: object types with virtual functions are usually implemented in C++ with a per-object pointer to a table of virtual functions which is unique to each type. If so inclined, a compiler for some hypothetical variant of C++ could implement assignment on objects (such as Base b; b = Derived()) as copying both the contents of the object and the virtual table pointer along with it, which would easily work if both Base and Derived were the same size. In the case that the two were not the same size, the compiler could even insert code that pauses the program for an arbitrary amount of time in order to rearrange memory in the program and update all possible references to that memory in a way that could be proven to have no detectable effect on the semantics of the program, terminating the program if no such rearrangement could be found: this would be very inefficient, though, and could not be guaranteed to ever halt, obviously not desirable features for an assignment operator to have.
So in lieu of the above, polymorphism in C++ is accomplished by allowing references and pointers to objects to reference and point to objects of their declared compile-time types and any subtypes thereof. When a virtual function is called through a reference or pointer, and the compiler cannot prove that the object referenced or pointed to is of a run-time type with a specific known implementation of that virtual function, the compiler inserts code which looks up the correct virtual function to call a run-time. It did not have to be this way, either: references and pointers could have been defined as being non-polymorphic (disallowing them to reference or point to subtypes of their declared types) and forcing the programmer to come up with alternative ways of implementing polymorphism. The latter is clearly possible since it's done all the time in C, but at that point there's not much reason to have a new language at all.
In sum, the semantics of C++ are designed in such a way to allow the high-level abstraction and encapsulation of object-oriented polymorphism while still retaining features (like low-level access and explicit management of memory) which allow it to be suitable for low-level development. You could easily design a language that had some other semantics, but it would not be C++ and would have different benefits and drawbacks.
I found it helpful to understand that a copy constructor is invoked when assigning like this:
class Base { };
class Derived : public Base { };
Derived x; /* Derived type object created */
Base y = x; /* Copy is made (using Base's copy constructor), so y really is of type Base. Copy can cause "slicing" btw. */
Since y is an actual object of class Base, rather than the original one, functions called on this are Base's functions.
Consider little endian architectures: values are stored low-order-bytes first. So, for any given unsigned integer, the values 0-255 are stored in the first byte of the value. Accessing the low 8-bits of any value simply requires a pointer to it's address.
So we could implement uint8 as a class. We know that an instance of uint8 is ... one byte. If we derive from it and produce uint16, uint32, etc, the interface remains the same for purposes of abstraction, but the one most important change is size of the concrete instances of the object.
Of course, if we implemented uint8 and char, the sizes may be the same, likewise sint8.
However, operator= of uint8 and uint16 are going to move different quantities of data.
In order to create a Polymorphic function we must either be able to:
a/ receive the argument by value by copying the data into a new location of the correct size and layout,
b/ take a pointer to the object's location,
c/ take a reference to the object instance,
We can use templates to achieve a, so polymorphism can work without pointers and references, but if we are not counting templates, then lets consider what happens if we implement uint128 and pass it to a function expecting uint8? Answer: 8 bits get copied instead of 128.
So what if we made our polymorphic function accept uint128 and we passed it a uint8. If our uint8 we were copying was unfortunately located, our function would attempt to copy 128 bytes of which 127 were outside of our accessible memory -> crash.
Consider the following:
class A { int x; };
A fn(A a)
{
return a;
}
class B : public A {
uint64_t a, b, c;
B(int x_, uint64_t a_, uint64_t b_, uint64_t c_)
: A(x_), a(a_), b(b_), c(c_) {}
};
B b1 { 10, 1, 2, 3 };
B b2 = fn(b1);
// b2.x == 10, but a, b and c?
At the time fn was compiled, there was no knowledge of B. However, B is derived from A so polymorphism should allow that we can call fn with a B. However, the object it returns should be an A comprising a single int.
If we pass an instance of B to this function, what we get back should be just a { int x; } with no a, b, c.
This is "slicing".
Even with pointers and references we don't avoid this for free. Consider:
std::vector<A*> vec;
Elements of this vector could be pointers to A or something derived from A. The language generally solves this through the use of the "vtable", a small addition to the object's instance which identifies the type and provides function pointers for virtual functions. You can think of it as something like:
template<class T>
struct PolymorphicObject {
T::vtable* __vtptr;
T __instance;
};
Rather than every object having its own distinct vtable, classes have them, and object instances merely point to the relevant vtable.
The problem now is not slicing but type correctness:
struct A { virtual const char* fn() { return "A"; } };
struct B : public A { virtual const char* fn() { return "B"; } };
#include <iostream>
#include <cstring>
int main()
{
A* a = new A();
B* b = new B();
memcpy(a, b, sizeof(A));
std::cout << "sizeof A = " << sizeof(A)
<< " a->fn(): " << a->fn() << '\n';
}
http://ideone.com/G62Cn0
sizeof A = 4 a->fn(): B
What we should have done is use a->operator=(b)
http://ideone.com/Vym3Lp
but again, this is copying an A to an A and so slicing would occur:
struct A { int i; A(int i_) : i(i_) {} virtual const char* fn() { return "A"; } };
struct B : public A {
int j;
B(int i_) : A(i_), j(i_ + 10) {}
virtual const char* fn() { return "B"; }
};
#include <iostream>
#include <cstring>
int main()
{
A* a = new A(1);
B* b = new B(2);
*a = *b; // aka a->operator=(static_cast<A*>(*b));
std::cout << "sizeof A = " << sizeof(A)
<< ", a->i = " << a->i << ", a->fn(): " << a->fn() << '\n';
}
http://ideone.com/DHGwun
(i is copied, but B's j is lost)
The conclusion here is that pointers/references are required because the original instance carries membership information with it that copying may interact with.
But also, that polymorphism is not perfectly solved within C++ and one must be cognizant of their obligation to provide/block actions which could produce slicing.
You need pointers or reference because for the kind of polymorphism you are interested in (*), you need that the dynamic type could be different from the static type, in other words that the true type of the object is different than the declared type. In C++ that happens only with pointers or references.
(*) Genericity, the type of polymorphism provided by templates, doesn't need pointers nor references.
When an object is passed by value, it's typically put on the stack. Putting something on the stack requires knowledge of just how big it is. When using polymorphism, you know that the incoming object implements a particular set of features, but you usually have no idea the size of the object (nor should you, necessarily, that's part of the benefit). Thus, you can't put it on the stack. You do, however, always know the size of a pointer.
Now, not everything goes on the stack, and there are other extenuating circumstances. In the case of virtual methods, the pointer to the object is also a pointer to the object's vtable(s), which indicate where the methods are. This allows the compiler to find and call the functions, regardless of what object it's working with.
Another cause is that very often the object is implemented outside of the calling library, and allocated with a completely different (and possibly incompatible) memory manager. It could also have members that can't be copied, or would cause problems if they were copied with a different manager. There could be side-effects to copying and all sorts of other complications.
The result is that the pointer is the only bit of information on the object that you really properly understand, and provides enough information to figure out where the other bits you need are.

Check if list of abstract elements contains an element of a certain derived type in C++? [duplicate]

I did find some questions already on StackOverflow with similar title, but when I read the answers, they were focusing on different parts of the question, which were really specific (e.g. STL/containers).
Could someone please show me, why you must use pointers/references for implementing polymorphism? I can understand pointers may help, but surely references only differentiate between pass-by-value and pass-by-reference?
Surely so long as you allocate memory on the heap, so that you can have dynamic binding, then this would have been enough. Obviously not.
"Surely so long as you allocate memory on the heap" - where the memory is allocated has nothing to do with it. It's all about the semantics. Take, for instance:
Derived d;
Base* b = &d;
d is on the stack (automatic memory), but polymorphism will still work on b.
If you don't have a base class pointer or reference to a derived class, polymorphism doesn't work because you no longer have a derived class. Take
Base c = Derived();
The c object isn't a Derived, but a Base, because of slicing. So, technically, polymorphism still works, it's just that you no longer have a Derived object to talk about.
Now take
Base* c = new Derived();
c just points to some place in memory, and you don't really care whether that's actually a Base or a Derived, but the call to a virtual method will be resolved dynamically.
In C++, an object always has a fixed type and size known at compile-time and (if it can and does have its address taken) always exists at a fixed address for the duration of its lifetime. These are features inherited from C which help make both languages suitable for low-level systems programming. (All of this is subject to the as-if, rule, though: a conforming compiler is free to do whatever it pleases with code as long as it can be proven to have no detectable effect on any behavior of a conforming program that is guaranteed by the standard.)
A virtual function in C++ is defined (more or less, no need for extreme language lawyering) as executing based on the run-time type of an object; when called directly on an object this will always be the compile-time type of the object, so there is no polymorphism when a virtual function is called this way.
Note that this didn't necessarily have to be the case: object types with virtual functions are usually implemented in C++ with a per-object pointer to a table of virtual functions which is unique to each type. If so inclined, a compiler for some hypothetical variant of C++ could implement assignment on objects (such as Base b; b = Derived()) as copying both the contents of the object and the virtual table pointer along with it, which would easily work if both Base and Derived were the same size. In the case that the two were not the same size, the compiler could even insert code that pauses the program for an arbitrary amount of time in order to rearrange memory in the program and update all possible references to that memory in a way that could be proven to have no detectable effect on the semantics of the program, terminating the program if no such rearrangement could be found: this would be very inefficient, though, and could not be guaranteed to ever halt, obviously not desirable features for an assignment operator to have.
So in lieu of the above, polymorphism in C++ is accomplished by allowing references and pointers to objects to reference and point to objects of their declared compile-time types and any subtypes thereof. When a virtual function is called through a reference or pointer, and the compiler cannot prove that the object referenced or pointed to is of a run-time type with a specific known implementation of that virtual function, the compiler inserts code which looks up the correct virtual function to call a run-time. It did not have to be this way, either: references and pointers could have been defined as being non-polymorphic (disallowing them to reference or point to subtypes of their declared types) and forcing the programmer to come up with alternative ways of implementing polymorphism. The latter is clearly possible since it's done all the time in C, but at that point there's not much reason to have a new language at all.
In sum, the semantics of C++ are designed in such a way to allow the high-level abstraction and encapsulation of object-oriented polymorphism while still retaining features (like low-level access and explicit management of memory) which allow it to be suitable for low-level development. You could easily design a language that had some other semantics, but it would not be C++ and would have different benefits and drawbacks.
I found it helpful to understand that a copy constructor is invoked when assigning like this:
class Base { };
class Derived : public Base { };
Derived x; /* Derived type object created */
Base y = x; /* Copy is made (using Base's copy constructor), so y really is of type Base. Copy can cause "slicing" btw. */
Since y is an actual object of class Base, rather than the original one, functions called on this are Base's functions.
Consider little endian architectures: values are stored low-order-bytes first. So, for any given unsigned integer, the values 0-255 are stored in the first byte of the value. Accessing the low 8-bits of any value simply requires a pointer to it's address.
So we could implement uint8 as a class. We know that an instance of uint8 is ... one byte. If we derive from it and produce uint16, uint32, etc, the interface remains the same for purposes of abstraction, but the one most important change is size of the concrete instances of the object.
Of course, if we implemented uint8 and char, the sizes may be the same, likewise sint8.
However, operator= of uint8 and uint16 are going to move different quantities of data.
In order to create a Polymorphic function we must either be able to:
a/ receive the argument by value by copying the data into a new location of the correct size and layout,
b/ take a pointer to the object's location,
c/ take a reference to the object instance,
We can use templates to achieve a, so polymorphism can work without pointers and references, but if we are not counting templates, then lets consider what happens if we implement uint128 and pass it to a function expecting uint8? Answer: 8 bits get copied instead of 128.
So what if we made our polymorphic function accept uint128 and we passed it a uint8. If our uint8 we were copying was unfortunately located, our function would attempt to copy 128 bytes of which 127 were outside of our accessible memory -> crash.
Consider the following:
class A { int x; };
A fn(A a)
{
return a;
}
class B : public A {
uint64_t a, b, c;
B(int x_, uint64_t a_, uint64_t b_, uint64_t c_)
: A(x_), a(a_), b(b_), c(c_) {}
};
B b1 { 10, 1, 2, 3 };
B b2 = fn(b1);
// b2.x == 10, but a, b and c?
At the time fn was compiled, there was no knowledge of B. However, B is derived from A so polymorphism should allow that we can call fn with a B. However, the object it returns should be an A comprising a single int.
If we pass an instance of B to this function, what we get back should be just a { int x; } with no a, b, c.
This is "slicing".
Even with pointers and references we don't avoid this for free. Consider:
std::vector<A*> vec;
Elements of this vector could be pointers to A or something derived from A. The language generally solves this through the use of the "vtable", a small addition to the object's instance which identifies the type and provides function pointers for virtual functions. You can think of it as something like:
template<class T>
struct PolymorphicObject {
T::vtable* __vtptr;
T __instance;
};
Rather than every object having its own distinct vtable, classes have them, and object instances merely point to the relevant vtable.
The problem now is not slicing but type correctness:
struct A { virtual const char* fn() { return "A"; } };
struct B : public A { virtual const char* fn() { return "B"; } };
#include <iostream>
#include <cstring>
int main()
{
A* a = new A();
B* b = new B();
memcpy(a, b, sizeof(A));
std::cout << "sizeof A = " << sizeof(A)
<< " a->fn(): " << a->fn() << '\n';
}
http://ideone.com/G62Cn0
sizeof A = 4 a->fn(): B
What we should have done is use a->operator=(b)
http://ideone.com/Vym3Lp
but again, this is copying an A to an A and so slicing would occur:
struct A { int i; A(int i_) : i(i_) {} virtual const char* fn() { return "A"; } };
struct B : public A {
int j;
B(int i_) : A(i_), j(i_ + 10) {}
virtual const char* fn() { return "B"; }
};
#include <iostream>
#include <cstring>
int main()
{
A* a = new A(1);
B* b = new B(2);
*a = *b; // aka a->operator=(static_cast<A*>(*b));
std::cout << "sizeof A = " << sizeof(A)
<< ", a->i = " << a->i << ", a->fn(): " << a->fn() << '\n';
}
http://ideone.com/DHGwun
(i is copied, but B's j is lost)
The conclusion here is that pointers/references are required because the original instance carries membership information with it that copying may interact with.
But also, that polymorphism is not perfectly solved within C++ and one must be cognizant of their obligation to provide/block actions which could produce slicing.
You need pointers or reference because for the kind of polymorphism you are interested in (*), you need that the dynamic type could be different from the static type, in other words that the true type of the object is different than the declared type. In C++ that happens only with pointers or references.
(*) Genericity, the type of polymorphism provided by templates, doesn't need pointers nor references.
When an object is passed by value, it's typically put on the stack. Putting something on the stack requires knowledge of just how big it is. When using polymorphism, you know that the incoming object implements a particular set of features, but you usually have no idea the size of the object (nor should you, necessarily, that's part of the benefit). Thus, you can't put it on the stack. You do, however, always know the size of a pointer.
Now, not everything goes on the stack, and there are other extenuating circumstances. In the case of virtual methods, the pointer to the object is also a pointer to the object's vtable(s), which indicate where the methods are. This allows the compiler to find and call the functions, regardless of what object it's working with.
Another cause is that very often the object is implemented outside of the calling library, and allocated with a completely different (and possibly incompatible) memory manager. It could also have members that can't be copied, or would cause problems if they were copied with a different manager. There could be side-effects to copying and all sorts of other complications.
The result is that the pointer is the only bit of information on the object that you really properly understand, and provides enough information to figure out where the other bits you need are.

Why doesn't polymorphism work without pointers/references?

I did find some questions already on StackOverflow with similar title, but when I read the answers, they were focusing on different parts of the question, which were really specific (e.g. STL/containers).
Could someone please show me, why you must use pointers/references for implementing polymorphism? I can understand pointers may help, but surely references only differentiate between pass-by-value and pass-by-reference?
Surely so long as you allocate memory on the heap, so that you can have dynamic binding, then this would have been enough. Obviously not.
"Surely so long as you allocate memory on the heap" - where the memory is allocated has nothing to do with it. It's all about the semantics. Take, for instance:
Derived d;
Base* b = &d;
d is on the stack (automatic memory), but polymorphism will still work on b.
If you don't have a base class pointer or reference to a derived class, polymorphism doesn't work because you no longer have a derived class. Take
Base c = Derived();
The c object isn't a Derived, but a Base, because of slicing. So, technically, polymorphism still works, it's just that you no longer have a Derived object to talk about.
Now take
Base* c = new Derived();
c just points to some place in memory, and you don't really care whether that's actually a Base or a Derived, but the call to a virtual method will be resolved dynamically.
In C++, an object always has a fixed type and size known at compile-time and (if it can and does have its address taken) always exists at a fixed address for the duration of its lifetime. These are features inherited from C which help make both languages suitable for low-level systems programming. (All of this is subject to the as-if, rule, though: a conforming compiler is free to do whatever it pleases with code as long as it can be proven to have no detectable effect on any behavior of a conforming program that is guaranteed by the standard.)
A virtual function in C++ is defined (more or less, no need for extreme language lawyering) as executing based on the run-time type of an object; when called directly on an object this will always be the compile-time type of the object, so there is no polymorphism when a virtual function is called this way.
Note that this didn't necessarily have to be the case: object types with virtual functions are usually implemented in C++ with a per-object pointer to a table of virtual functions which is unique to each type. If so inclined, a compiler for some hypothetical variant of C++ could implement assignment on objects (such as Base b; b = Derived()) as copying both the contents of the object and the virtual table pointer along with it, which would easily work if both Base and Derived were the same size. In the case that the two were not the same size, the compiler could even insert code that pauses the program for an arbitrary amount of time in order to rearrange memory in the program and update all possible references to that memory in a way that could be proven to have no detectable effect on the semantics of the program, terminating the program if no such rearrangement could be found: this would be very inefficient, though, and could not be guaranteed to ever halt, obviously not desirable features for an assignment operator to have.
So in lieu of the above, polymorphism in C++ is accomplished by allowing references and pointers to objects to reference and point to objects of their declared compile-time types and any subtypes thereof. When a virtual function is called through a reference or pointer, and the compiler cannot prove that the object referenced or pointed to is of a run-time type with a specific known implementation of that virtual function, the compiler inserts code which looks up the correct virtual function to call a run-time. It did not have to be this way, either: references and pointers could have been defined as being non-polymorphic (disallowing them to reference or point to subtypes of their declared types) and forcing the programmer to come up with alternative ways of implementing polymorphism. The latter is clearly possible since it's done all the time in C, but at that point there's not much reason to have a new language at all.
In sum, the semantics of C++ are designed in such a way to allow the high-level abstraction and encapsulation of object-oriented polymorphism while still retaining features (like low-level access and explicit management of memory) which allow it to be suitable for low-level development. You could easily design a language that had some other semantics, but it would not be C++ and would have different benefits and drawbacks.
I found it helpful to understand that a copy constructor is invoked when assigning like this:
class Base { };
class Derived : public Base { };
Derived x; /* Derived type object created */
Base y = x; /* Copy is made (using Base's copy constructor), so y really is of type Base. Copy can cause "slicing" btw. */
Since y is an actual object of class Base, rather than the original one, functions called on this are Base's functions.
Consider little endian architectures: values are stored low-order-bytes first. So, for any given unsigned integer, the values 0-255 are stored in the first byte of the value. Accessing the low 8-bits of any value simply requires a pointer to it's address.
So we could implement uint8 as a class. We know that an instance of uint8 is ... one byte. If we derive from it and produce uint16, uint32, etc, the interface remains the same for purposes of abstraction, but the one most important change is size of the concrete instances of the object.
Of course, if we implemented uint8 and char, the sizes may be the same, likewise sint8.
However, operator= of uint8 and uint16 are going to move different quantities of data.
In order to create a Polymorphic function we must either be able to:
a/ receive the argument by value by copying the data into a new location of the correct size and layout,
b/ take a pointer to the object's location,
c/ take a reference to the object instance,
We can use templates to achieve a, so polymorphism can work without pointers and references, but if we are not counting templates, then lets consider what happens if we implement uint128 and pass it to a function expecting uint8? Answer: 8 bits get copied instead of 128.
So what if we made our polymorphic function accept uint128 and we passed it a uint8. If our uint8 we were copying was unfortunately located, our function would attempt to copy 128 bytes of which 127 were outside of our accessible memory -> crash.
Consider the following:
class A { int x; };
A fn(A a)
{
return a;
}
class B : public A {
uint64_t a, b, c;
B(int x_, uint64_t a_, uint64_t b_, uint64_t c_)
: A(x_), a(a_), b(b_), c(c_) {}
};
B b1 { 10, 1, 2, 3 };
B b2 = fn(b1);
// b2.x == 10, but a, b and c?
At the time fn was compiled, there was no knowledge of B. However, B is derived from A so polymorphism should allow that we can call fn with a B. However, the object it returns should be an A comprising a single int.
If we pass an instance of B to this function, what we get back should be just a { int x; } with no a, b, c.
This is "slicing".
Even with pointers and references we don't avoid this for free. Consider:
std::vector<A*> vec;
Elements of this vector could be pointers to A or something derived from A. The language generally solves this through the use of the "vtable", a small addition to the object's instance which identifies the type and provides function pointers for virtual functions. You can think of it as something like:
template<class T>
struct PolymorphicObject {
T::vtable* __vtptr;
T __instance;
};
Rather than every object having its own distinct vtable, classes have them, and object instances merely point to the relevant vtable.
The problem now is not slicing but type correctness:
struct A { virtual const char* fn() { return "A"; } };
struct B : public A { virtual const char* fn() { return "B"; } };
#include <iostream>
#include <cstring>
int main()
{
A* a = new A();
B* b = new B();
memcpy(a, b, sizeof(A));
std::cout << "sizeof A = " << sizeof(A)
<< " a->fn(): " << a->fn() << '\n';
}
http://ideone.com/G62Cn0
sizeof A = 4 a->fn(): B
What we should have done is use a->operator=(b)
http://ideone.com/Vym3Lp
but again, this is copying an A to an A and so slicing would occur:
struct A { int i; A(int i_) : i(i_) {} virtual const char* fn() { return "A"; } };
struct B : public A {
int j;
B(int i_) : A(i_), j(i_ + 10) {}
virtual const char* fn() { return "B"; }
};
#include <iostream>
#include <cstring>
int main()
{
A* a = new A(1);
B* b = new B(2);
*a = *b; // aka a->operator=(static_cast<A*>(*b));
std::cout << "sizeof A = " << sizeof(A)
<< ", a->i = " << a->i << ", a->fn(): " << a->fn() << '\n';
}
http://ideone.com/DHGwun
(i is copied, but B's j is lost)
The conclusion here is that pointers/references are required because the original instance carries membership information with it that copying may interact with.
But also, that polymorphism is not perfectly solved within C++ and one must be cognizant of their obligation to provide/block actions which could produce slicing.
You need pointers or reference because for the kind of polymorphism you are interested in (*), you need that the dynamic type could be different from the static type, in other words that the true type of the object is different than the declared type. In C++ that happens only with pointers or references.
(*) Genericity, the type of polymorphism provided by templates, doesn't need pointers nor references.
When an object is passed by value, it's typically put on the stack. Putting something on the stack requires knowledge of just how big it is. When using polymorphism, you know that the incoming object implements a particular set of features, but you usually have no idea the size of the object (nor should you, necessarily, that's part of the benefit). Thus, you can't put it on the stack. You do, however, always know the size of a pointer.
Now, not everything goes on the stack, and there are other extenuating circumstances. In the case of virtual methods, the pointer to the object is also a pointer to the object's vtable(s), which indicate where the methods are. This allows the compiler to find and call the functions, regardless of what object it's working with.
Another cause is that very often the object is implemented outside of the calling library, and allocated with a completely different (and possibly incompatible) memory manager. It could also have members that can't be copied, or would cause problems if they were copied with a different manager. There could be side-effects to copying and all sorts of other complications.
The result is that the pointer is the only bit of information on the object that you really properly understand, and provides enough information to figure out where the other bits you need are.

C++ Objects: When should I use pointer or reference

I can use an object as pointer to it, or its reference. I understand that the difference is that pointers have to be deleted manually, and references remain until they are out of scope.
When should I use each of them? What is the practical difference?
Neither of these questions answered my doubts:
Pointer vs. Reference
C++ difference between reference, objects and pointers
A reference is basically a pointer with restrictions (has to be bound on creation, can't be rebound/null). If it makes sense for your code to use these restrictions, then using a reference instead of a pointer allows the compiler to warn you about accidentally violating them.
It's a lot like the const qualifier: the language could exist without it, it's just there as a bonus feature of sorts that makes it easier to develop safe code.
"pointers I have to delete and reference they remain until their scope finish."
No, that's completely wrong.
Objects which are allocated with new must be deleted[*]. Objects which are not allocated with new must not be deleted. It is possible to have a pointer to an object that was not allocated with new, and it is possible to have a reference to an object that was allocated with new.
A pointer or a reference is a way of accessing an object, but is not the object itself, and has no bearing on how the object was created. The conceptual difference is that a reference is a name for an object, and a pointer is an object containing the address of another object. The practical differences, how you choose which one to use, include the syntax of each, and the fact that references can't be null and can't be reseated.
[*] with delete. An array allocated with new[] must be deleted with delete[]. There are tools available that can help keep track of allocated resources and make these calls for you, called smart pointers, so it should be quite rare to explicitly make the call yourself, as opposed to just arranging for it to be done, but nevertheless it must be done.
suszterpatt already gave a good explanation. If you want a rule of thumb that is easy to remember, I would suggest the following:
If possible use references, use pointers only if you can not avoid them.
Even shorter: Prefer references over pointers.
Here's another answer (perhaps I should've edited the first one, but since it has a different focus, I thought it would be OK to have them separate).
When you create a pointer with new, the memory for it is reserved and it persists until you call delete on it - but the identifier's life span is still limited to the code block's end. If you create objects in a function and append them to an external list, the objects may remain safely in the memory after the function returns and you can still reference them without the identifier.
Here's a (simplified) example from Umbra, a C++ framework I'm developing. There's a list of modules (pointers to objects) stored in the engine. The engine can append an object to that list:
void UmbraEngine::addModule (UmbraModule * module) {
modules.push(module);
module->id = modules.size() - 1;
}
Retrieve one:
UmbraModule * UmbraEngine::getModule (int id) {
for (UmbraModule **it=modules.begin(); it != modules.end(); it++) {
if ((*it)->id == id) return *it;
}
}
Now, I can add and get modules without ever knowing their identifiers:
int main() {
UmbraEngine e;
for (int i = 0; i < 10; i++) {
e.addModule(new UmbraModule());
}
UmbraModule * m = e.getModule(5); //OK
cout << m << endl; //"0x127f10" or whatever
for (int j = 0; k < 10; j++) {
UmbraModule mm; //not a pointer
e.addModule(&mm);
}
m = e.getModule(15);
cout << m << endl; //{null}
}
The modules list persists throughout the entire duration of the program, I don't need to care about the modules' life span if they're instantiated with new :). So that's basically it - with pointers, you can have long-lived objects that don't ever need an identifier (or a name, if you will) in order to reference them :).
Another nice, but very simple example is this:
void getVal (int * a) {
*a = 10;
}
int main() {
int b;
getVal(&b);
return b;
}
You have many situations wherein a parameter does not exist or is invalid and this can depend on runtime semantics of the code. In such situations you can use a pointer and set it to NULL (0) to signal this state. Apart from this,
A pointer can be re-assigned to a new
state. A reference cannot. This is
desirable in some situations.
A pointer helps transfer owner-ship semantics. This is especially useful
in multi-threaded environment if the parameter-state is used to execute in
a separate thread and you do not usually poll till the thread has exited. Now the thread can delete it.
Erm... not exactly. It's the IDENTIFIER that has a scope. When you create an object using new, but its identifier's scope ends, you may end up with a memory leak (or not - depends on what you want to achieve) - the object is in the memory, but you have no means of referencing it anymore.
The difference is that a pointer is an address in memory, so if you have, say, this code:
int * a = new int;
a is a pointer. You can print it - and you'll get something like "0x0023F1" - it's just that: an address. It has no value (although some value is stored in the memory at that address).
int b = 10;
b is a variable with a value of 10. If you print it, you'll get 10.
Now, if you want a to point to b's address, you can do:
a = &b; //a points to b's address
or if you want the address pointed by a to have b's value:
*a = b; //value of b is assigned to the address pointed by a
Please compile this sample and comment/uncomment lines 13 and 14 to see the difference (note WHERE the identifiers point and to WHAT VALUE). I hope the output will be self-explanatory.
#include <iostream>
using namespace std;
int main()
{
int * a = new int;
int b = 10;
cout << "address of a: " << a << endl;
cout << "address of b: " << &b << endl;
cout << "value of a: " << *a << endl;
cout << "value of b: " << b << endl;
a = &b; //comment/uncomment
//*a = b; //comment/uncomment
cout << "address of a: " << a << endl;
cout << "address of b: " << &b << endl;
cout << "value of a: " << *a << endl;
cout << "value of b: " << b << endl;
}
Let's answer the last question first. Then the first question will make more sense.
Q: "What is the practical difference[ between a pointer and a reference]?"
A: A reference is just a local pseudonym for another variable. If you pass a parameter by reference, then that parameter is exactly the same variable as the one that was listed in the calling statement. However, internally there usually is no difference between a pointer and a reference. References provide "syntax sugar" by allowing you to reduce the amount of typing you have to do when all you really wanted was access to a single instance of a given variable.
Q: "When should I use each of em?"
A: That's going to be a matter of personal preference. Here's the basic rule I follow. If I'm going to need to manipulate a variable in another scope, and that variable is either an intrinsic type, a class that should be used like an intrinsic type (i.e. std::string, etc...), or a const class instance, then I pass by reference. Otherwise, I'll pass by pointer.
The thing is you cannot rebind a reference to another object. References are bound compile time and cannot be null or rebound. So pointers aren't redundant if your doubt was that :)
As my c++ teacher used to put it, pointers point to the memory location while references are aliases . Hence the main advantage is that they can be used in the same way as the object's name they refer to, but in a scope where the object is not available by passing it there.
While pointers can be redirected to some other location, references being like constant pointers, can't be redirected. So references cant be used for traversing arrays in a functions etc.
However a pointer being a separate entity takes up some memory, but the reference being the same as the referred object doesn't take any additional space. This is one of its advantages.
I have also read that the processing time for references are less,
as
int & i = b ;
i++ ; takes lesser time than
int * j = b ;
(*j) ++ ;
but I am yet to confirm this. If anyone can throw light on this claim it would be great.
Comments are welcome :)