Вопрос

Вызовет ли это двусмысленность?:

class A { ... };
class B : public A {
//...
B(const B& b);
B(const A& a);
//...
};
Это было полезно?

Решение

Обновление: Похоже, что asker вытирается названия классов с вопроса. Вот оригинальный кусок кода, для которого написан этот ответ:

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

Я сказал «нет» раньше, но я передумал. Это неоднозначно, и я не могу думать о веских основаниях иметь Vector3D наследует от Vector2D.

с математической перспективы, 2D векторное пространство может быть продлено до 3D векторного пространства, но есть много расширений на выбор - они не уникальны. Поэтому, когда вы делаете 3D векторный класс, который наследует от 2D векторного класса, вы делаете одно встраивание 2D пространства в 3D-пространстве «Привилегированные» и все остальные вложения ниже. Я не думаю, что это особенно полезно.

Другое, что вы делаете, это вы говорите, что «каждый 3D вектор - это 2D вектор», который просто глупо. Например, может быть, вы написали функцию:

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

Давайте предположим, что вы забыли , чтобы написать версию для 3D векторов. Теперь компилятор не сможет дать вам сообщение об ошибке: вместо этого ваши 3D-векторы будут проецироваться в 2D-пространство, используя «привилегированную» проекцию, которую вы решили при создании класса, и вы получите неправильный ответ. Теперь предположим, что вы добавляете другую функцию:

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

Теперь есть еще проблема.

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

Это будет использовать 2D проекцию X, и снова вы не получите предупреждение компилятора. Вы просто получите неправильный ответ.

Сводка: Это худшая вида двусмысленность: это такая двусмысленность, когда компилятор даст вам ответ, который вы не ожидаете.

vector3d не должен наследоваться от Vector2D. Это математически нелогично.

Другие советы

При выборе между перегруженными конструкторами, которые принимают ссылки на базовый и производный типы, обычно нет никакой двусмысленности.

Если параметр имеет тип, производный от базового типа (A), но не производного типа (B) или тип, производный от производного типа, тогда, очевидно, только конструктор, принимающий ссылку на base, является совпадением.

Если параметр имеет производный тип, то преобразование, необходимое для вызова конструктора, использующего базовый класс, требует преобразования производного типа в базовый тип в точке, где вызов конструктора, использующего ссылку на производный тип, требует только преобразования идентификатора, поэтому последнее лучше подходит.

Если параметр относится к классу, производному от производного типа (B) затем конструктор, принимающий производный тип (B) по-прежнему лучше подходит, потому что стандарт гласит, что привязка к ссылке производного типа лучше, чем привязка к ссылке базового типа этого типа.(ISO/IEC 14882:2011 13.3.3.2 / 4 - Ранжирование последовательностей неявного преобразования [over.ics.rank])

Очевидно, что вы все еще можете создавать двусмысленности, если будете достаточно стараться.

Напр.

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

S s;
B b(s);

Оператор & генерирует ссылки.

В вашем случае первый тип - это ссылка на тип Vector3D, другой - ссылка на тип Vector2D, поэтому это разные типы.

Поскольку это разные типы, они будут отличать подпись вашего конструктора, а также не будут создавать двусмысленности.

Ответ - нет.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top