Casey
Casey

Reputation: 10936

C++: Constructor ambiguity

Will this cause an ambiguity?:

class A { ... };
class B : public A {
//...
B(const B& b);
B(const A& a);
//...
};

Upvotes: 0

Views: 571

Answers (3)

Dietrich Epp
Dietrich Epp

Reputation: 213298

Update: It appears that the asker has scrubbed the class names from the question. Here is the original piece of code for which this answer is written:

class Vector2D { ... };
class Vector3D : public Vector2D {
//...
Vector3D(const Vector2D& b);
Vector3D(const Vector3D& a);
//...
};

I said "no" earlier, but I changed my mind. This is ambiguous, and I can't think of a good reason to have Vector3D inherit from Vector2D.

From a mathematical perspective, a 2D vector space can be extended to a 3D vector space, but there are many extensions to choose from -- they are not unique. So when you make a 3D vector class that inherits from a 2D vector class, you are making one embedding of the 2D space in the 3D space "privileged" and all other embeddings inferior. I don't think that's particularly useful.

The other thing that you are doing is you are saying that "every 3D vector is a 2D vector", which is just kind of silly. For example, maybe you write a function:

// Compute the angle between two vectors
double angle(Vector2D x, Vector2D y);

Let's suppose that you forgot to write the version for 3D vectors. Now, the compiler won't be able to give you an error message: instead, your 3D vectors will get projected into 2D space using the "privileged" projection you chose when creating the class, and you will get the wrong answer. Now suppose you add another function:

// Compute the angle between two 3D vectors
double angle(Vector3D x, Vector3D y);

Now, there's still a problem.

Vector3D x = ...;
Vector2D y = ...;
double a = angle(x, y);

This will use the 2D projection of x, and again, you won't get a compiler warning. You'll just get the wrong answer.

Summary: This is the worst kind of ambiguity: it is the kind of ambiguity where the compiler will give you the answer that you don't expect.

Vector3D should not inherit from Vector2D. It is mathematically illogical.

Upvotes: 4

CB Bailey
CB Bailey

Reputation: 791631

When choosing between overloaded constructors that take references to a base and a derived type there is usually no ambiguity.

If the parameter is of a type derived from the base type (A) but not of the derived type (B) or a type derived from the derived type then obviously only the constructor taking a reference to base is a match.

If the parameter is of the derived type then the conversion required to call the constructor taking the base class requires a derived-to-base type at the point where the call to the constuctor taking a reference to derived type only requires an identity conversion so the latter is a better match.

If the parameter is of a class derived from the derived type (B) then the constructor taking the derived type (B) is still a better match because the standard says that binding to a reference of a derived type is better than binding to a reference of a base of that type. (ISO/IEC 14882:2011 13.3.3.2 / 4 - Ranking implicit conversion sequences [over.ics.rank])

Obviously you can still generate ambiguities if you try hard enough.

E.g.

struct S {
    operator A() const;
    operator B() const;
};

S s;
B b(s);

Upvotes: 2

user827992
user827992

Reputation: 1753

The operator & generates references.

In your case the first type is a reference to a Vector3D type, the other one is a reference to a Vector2D type, so they are different types.

Since they are different types, they will make the signature of your constructor differ and also they will not generate ambiguity.

The answer is No.

Upvotes: 1

Related Questions