2

I am working on a c++ project. I need to put into a std::vector different classes. I found (Objects of different classes in a single vector?) that it is possible to do this by creating classes with a common type and then putting pointers to the vector. In this case I could cast the pointers to the type I need. This is clear to me.

It is also mentioned that in principle it is possible to use not just pointers but smart_pointers, i.e std::vector<std::unique_ptr<TMyClass>>. And this is where my problems start. TMyClass has the indexing operator (operator[]).

Lets say I have std::vector<std::unique_ptr<TMyClass>> A. I try to access an element of the TMyClass object like this A[0][0] or A[0].get()[0] or (A[0])[0] but when I compile I get an error:

[bcc64 Error] type 'value_type' (aka 'std::unique_ptr<.....>') does not provide a subscript operator

How can I tell the compiler that the second index is related to TMyClass object and not to the unique_ptr? I would highly appreciate if somebody explains me how to access elements in this case.

Alexander
  • 43
  • 5

2 Answers2

4

You need to extract pointer first

A[0]  //type: std::unique_ptr<TMyClass>&

Then extract object from that pointer (pointee)

*A[0] //type: TMyClass&

And then you can use your overloaded operators on this object

(*A[0])[0] 
Yksisarvinen
  • 18,008
  • 2
  • 24
  • 52
  • thanks for your reply! This seems to work. With `(*A[0])[0]` I get basically the access to the element. And I need to cast it to another type is `(TMyClass2*)(&(*A[0])[0])` a proper way to do this or can it be done in an easier way? – Alexander May 06 '20 at 11:25
  • @Alexander Don't use C-style casts, this is asking for trouble. What is the type of `(*A[0])[0]`? How does it convert to `TMyClass2`? – Yksisarvinen May 06 '20 at 11:32
  • @Alexander At the very least, I suggest creating a named variable (probably a reference) before using `(*A[0])[0]` or it will quickly become a syntax hell. Something like this: `auto& myObject = (*A[0])[0];` – Yksisarvinen May 06 '20 at 11:33
  • `(*A[0])[0]` has type of `TMyClass`. Basically `struct TMyClass2 : public TMyClass {}`. `TMyClass2` cointains more variables. – Alexander May 06 '20 at 11:36
  • @Alexander Show the definitions of `TMyClass` and `TMyClass2` in your question. Does the base class have virtual functions that you implement in `TMyClass2`? If so, you don't need to cast, just call them. – Ted Lyngmo May 06 '20 at 11:38
  • @Ted Lyngmo Both `TMyClass` and `TMyClass2` have no functions just variables. – Alexander May 06 '20 at 11:39
  • 1
    @Alexander So your operator is like `TMyClass& TMyClass::operator[](size_t)`? If you really need to cast, use `dynamic_cast(&((*A[0])[0]));`, but downcasting classes to derived ones is a bad smell. It suggests that something is wrong with your design. – Yksisarvinen May 06 '20 at 11:40
  • 1
    @Alexander I think this answer should be accepted since it solves the problem you asked about. The casting problem is different problem. Ask a new question for that if you can't find an answer for it here on SO already. – Ted Lyngmo May 06 '20 at 11:43
  • @Yksisarvinen I am sorry I made a mistake in my previous comments. `TMyClass` has an array of type `TMyClass2[]` and the `TMyClass2 operator[](size_t)`. `TMyClass2` has only variables with no functions. `(*A[0])[0]` has type of `TMyClass2` and this type I need to convert to another class `TMyClass3: public TMyClass2`. – Alexander May 06 '20 at 11:48
1

Pointers must be dereferenced. So, I would guess (*A[0])[0] or A[0]->[0]. Not nice looking, but that's pointers for you

  • 1
    Did you ever try `A[0]->[0]`? If you want to go this way, I would suggest `A[0]->operator[](0)` instead. ;-) (But `(*A[0])[0]` looks somehow more compact and convenient.) – Scheff's Cat May 06 '20 at 11:17
  • @Yaroslav Fyodorov Thanks for your comments! With `(*A[0])[0]` I get basically the access to the element. And I need to cast it to another type is `(TMyClass2*)(&(*A[0])[0])` a proper way to do this or can it be done in an easier way? – Alexander May 06 '20 at 11:29
  • Perhaps I need to refresh my cpp. It somehow got contaminated by Perl why I wasn't using either of them. I knew [0]->[0] doesn't look c++ enough – Yaroslav Fyodorov May 06 '20 at 11:39
  • @Alexander I am getting confused here. Now there is TMyClass2 out of the blue. Who inherits from whom? And which vector holds pointers to base class? Based on your initial question I would think you want to do `A[0]` to access the shared_ptr obj `A[0].get()` to get the underlining pointer, and `(TMyClass2*)A[0].get()` to cast it. That is based on the assumption that TMyClass2 inherits from TMyClass. But then I am not sure what indexing operator on TMyClass got to do with that. – Yaroslav Fyodorov May 06 '20 at 11:48
  • @Alexander If what you wrote in the comments to your question, that is `TMyClass` has an array of type `TMyClass2[]` and the `TMyClass2 operator[](size_t)` is correct, then you cannot cast object returned by `(*A[0])[0]` because it's not a pointer and not a reference. In any case, array of type `TMyClass2[]` cannot possibly hold objects of class `TMyClass3: TMyClass2` – Yaroslav Fyodorov May 06 '20 at 11:59