简体   繁体   中英

Why does it not make sense to have an array of references, and how can I have an array of polymorphic objects, without pointers?

In C++, it's illegal to have arrays of references. In a question about it , the second voted answer claims that "References are not objects. They don't have storage of their own, they just reference existing objects. For this reason it doesn't make sense to have arrays of references.".

Firstly, I'd like to understand why it doesn't make sense to have an array of references.

My assumption for why that might be is, that anywhere a reference is used, it is automatically 'translated' to the object it references. So saying arrayOfReferences[5] = refToObj is equivalent to saying arrayOfReferences[5] = obj . resToObj is always implicitly translated to obj . So making an array of references to object, is equivalent to simply making an array of objects. Is this assumption correct?

If it is, than I have another question:

In C++, if we want polymorphism we can use either pointers or references. Storing an object of a Thing subclass in a Thing* allows us polymorphism, and so does storing it in a Thing& . However storing it in a Thing 'slices' the extra non- Thing stuff, and leaves us with a plain Thing .

So if we agree that an array of references is equivalent to an array of objects - great, I can just use a normal array of objects. But than - I lose polymorphism. I can store all kinds of Thing objects in a Thing[] , but they will all be sliced to a simple Thing .

So, the second question is: is there a way to store objects in an array and retain their concrete type and polymorphism, without using pointers (ie Thing*[] )?

is there a way to store objects in an array and retain their concrete type and polymorphism, without using pointers (ie Thing*[])?

Yes (but not directly). Have a look at this (disclaimer: the link is to one of my own posts). The post proposes a class that wraps a reference (similar to std::reference_wrapper) that also implements deep copy semantics for the refered-to object.

The answer is both Yes and No, let me elaborate.

First, references are not like objects themselves, they are actually like pointers with nicer syntax. So array of references would be equivalent to array of pointers.

Second you should understand that this is not about array or pointers, but terminology of types:

is there a way ... retain their concrete type and polymorphism

In this context (C++) (dynamic) polymorphism means concrete type is knot known. Only interface is known and it's implementation varies with different subtypes. This is the way to implement polymorphism. So using concrete types will not allow polymorphism.

That said you can implement "Smart pointers" yourself in a form of "Clever references" and store their values in an array, say of type

CleverReference<IThing>[]

Check std::unique_ptr / std::shared_ptr and have a look at Jeff Elgers' "invisible pointers"

According to the C++ISO definition , There shall be no references to references, no arrays of references, and no pointers to references.

http://en.wikipedia.org/wiki/Reference_(C%2B%2B)#ISO_definition

There shall be no references to references, no arrays of references , and no pointers to references. The declaration of a reference shall contain an initializer (8.5.3) except when the declaration contains an explicit extern specifier (7.1.1), is a class member (9.2) declaration within a class declaration, or is the declaration of a parameter or a return type (8.3.5); see 3.1. A reference shall be initialized to refer to a valid object or function. [Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer, which causes undefined behavior. As described in 9.6, a reference cannot be bound directly to a bitfield. ] —ISO/IEC 14882:1998(E), the ISO C++ standard, in section 8.3.2 [dcl.ref]

Let me be the first to suggest you use a smart pointer. Here is an example to get you started:

std::vector<std::unique_ptr<Thing>> v;

v.push_back(std::make_unique<NumberThing>(42));
v.push_back(std::make_unique<StringThing>("hello"));

for (auto&& thing : v)
{
    thing->doYourThing();
}

Note the complete absence of new and delete here, it's all taken care of for you by the system.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM