tags:

views:

111

answers:

4

If B is subclass of A.

And I have in main():

B** b = new B*[10];
... // some algorithm that does b[i] = new B(..);

So I have an array of pointers to objects B.

Then I have a function:

void f(A** foo);

If in main, I do: f(b); I get a warning, but obviously if I do: f((A**)b);, I don't.

The (A**) its a bit nasty. I was wondering if there's a more elegant way in C++ that at least do type checking as dynamic_cast.

I want foo to sort (only using swaps) arrays of objects of type A or subclass.. so make a generic sorting algorithm. I hope now you understand better my problem.

+2  A: 

A** and B** are two totally different types. Just because there is an implicit conversion from B* to A* does not mean that the same conversion exists from B** to A** See this FAQ Converting Derived* → Base* works OK; why doesn't Derived** → Base** work? for more details.

Naveen
Thanks, but I cannot solve my problem. I want to A have a function that sorts arrays of type A and all subclasses of A. What is the right way to do it?
ritmbo
@ritmbo: is this something similar to what you want to do: http://codepad.org/DlErsYLj
Naveen
I cannot use vector
ritmbo
@ritmbo: Updated, not using vector: http://codepad.org/4oo53bHt
Naveen
I have to programm the sorting algorithm manually :S
ritmbo
@ritmbo: it sounds like this is a homework problem, if you can't use std::vector or std::sort. Is that correct?
Bill
Yes, that's correct
ritmbo
+1  A: 

The case is incorrect. Suppose the function is (perfectly legitimate):

void f(A** foo)
{
  foo[0] = new A();
}

now if you passed a B** instead, the first pointer (which the compiler is certain is a B*) has suddenly become an A* -- terrible type-violation, hard-crash likely soon.

A** -- no const in sight, please notice! -- means a mutable pointer to mutable pointers to A, which is why setting one of those pointers to a new pointer to A is perfectly OK. But you can't do that if you actually have a B** -- those pointers must always be to B (or subclass thereof), not to A, a superclass of B.

Yep, it's covariance vs contra-variance all over again -- under mutability (no const in sight), it's really a minefield. Why not stick in all the const you can possibly afford? This will also indicate which casts make sense under which circumstances!

Alex Martelli
My problem is that the f, only swap things of the array. So if I use const, then i cant do what I want to do.
ritmbo
+2  A: 

There's a reason you get a warning or error if you try to implicitly cast a B** to a A**: it's not safe to do so.

Referring to the array as a A** allows you to put pointers to A objects inside. For an array of B* this is wrong and therefor the cast is unsafe.

Maybe f would better be a template function:

template<typename T>
void f(T **array) {
   ...
}
sth
Also, although C++ doesn't (yet) allow you to explicitly limit T to subtypes of A, when you pass T* actual parameters to a compare function that accepts A* formal parameters, the compiler will indeed enforce that T is derived (publicly) from A.
Ben Voigt
@BenVoigt: you could use an implicit cast inside the function without calling another function... like: `Base* elem = array[i];` which wont compile if array is not derived from Base
smerlin
@smerlin: Yes, the comparison logic could be right inside the sort function. But the inline keyword is so effective, and you get so much extra reusability from separating the sort logic from the ordering, that using a compare function is a good habit and definitely to be encouraged when teaching programming.
Ben Voigt
A: 

If B is a subclass of A then you can still sort a list of pointers to objects of type B even if the type of the array is "array of pointers to A".

E.g.

A** ptrToBs = new A*[10];

ptrToBs[0] = &b01; // ... or new B
ptrToBs[1] = &b02;

// ...

ptrToBs[9] = &b10;

f(ptrToBs);

However, what you say you want is a generic algorithm to swap objects, not pointers based on the value of the pointed-to objects. In this case, you are better off having a function template.

template< class T >
void f(T* t)
{
    // ...
}

This way you can sort an array of A or and array of B without having to have an array of pointer to exactly the right type; you can just sort an array of A or B objects or anything else provided that the type of objects that you are sort support the operations that you are using in your sort algorithm.

Typically you would want to pass the size of the array or a pointer to the end of the array so that the algorithm doesn't have to assume how big the array is.

template< class T > void f(T* arr, std::size_t size);

or

template< class T > void f(T* first, T* last);
Charles Bailey