Неявное приведение C++

Рассмотрим этот случай:

ClassA obA;
ClassB obB;

obA = obB;

Правильно ли, что если ClassA имеет конструктор, который имеет параметр типа ClassB, это будет называться в этом случае?

Если есть перегруженный оператор приведения ClassB - который преобразует ClassB Возражать ClassA объект, метод оператора будет вызван. Если есть соответствующий конструктор и перегруженный оператор приведения, какой из них будет вызван? Где я могу прочитать об этом?

2 ответа

Решение

Правильно ли, что если ClassA имеет конструктор, который имеет параметр типа ClassB, это будет называться в этом случае?

Да, конструкторы рассматриваются для неявных преобразований типов:

Преобразования типов объектов класса могут быть определены конструкторами и функциями преобразования. Эти преобразования называются пользовательскими преобразованиями и используются для неявных преобразований типов (раздел 4), для инициализации (8.5) и для явных преобразований типов (5.4, 5.2.9).

Конструктор с подписью ClassA::ClassA(ClassB) называется конвертирующим конструктором. Во время вызова функции, такого как назначение, конструкторы и определяемые пользователем операторы преобразования компилируются в набор перегрузки, и для преобразования выбирается лучший из них.

Если выбран конструктор: если тип источника является типом по значению, он создает тип значения типа источника (ClassA) инициализируется с типом типа назначения (ClassB), и это используется для инициализации параметра. Если тип источника является ссылкой, используются правила инициализации ссылки.


Операторы присваивания неявно генерируются в ClassA (при условии, что они не были переопределены). Они есть:

ClassA& operator=(ClassA const&);
ClassA& operator=(ClassA      &&);

Последовательность неявного преобразования может выбрать конструктор или функцию преобразования для преобразования ClassB -> ClassA const& или же ClassB -> ClassA&&,

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

struct B { operator struct A(); };

struct A {
    A() = default;
    A(B) {}
};

B::operator A() { return A(); }

int main() 
{
    A a; B b;
    a = b; // Error! Ambiguous conversion
}

И то и другое A::A(B) а также B::operator A() обе жизнеспособные функции преобразования для использования в преобразовании. Таким образом, преобразование неоднозначно, и мы получаем ошибку компиляции.

Определяемые пользователем преобразования применяются только в том случае, если они однозначны (10.2, 12.3.2).

Если мы изменим сигнатуру конвертирующего конструктора в классе A в A::A(B const&)затем оператор преобразования в B будет использоваться, потому что AДля конструктора требуется преобразование квалификации (добавление const).

На cppreference есть ветка, где вы можете узнать больше.

Этот код:

ClassA obA;
ClassB obB;

obA = obB;

это не то, что вы думаете (*). Этот код:

ClassB obB;
ClassA  obA = obB;

будет работать (как предусмотрено), если:

1. ClassA имеет конструктор, который принимает ClassB в качестве параметра:

class ClassA
{
public:
    ClassA(const ClassB& b)
    {
        //construct *this from b
    }
};

2. ClassB определил оператор преобразования в тип:

class ClassB
{
public:
    operator ClassA() const
    {
        //construct ClassA from *this
    }
};

Если в ClassA есть перегруженный оператор приведения, у которого есть параметр типа ClassB [...].

Вы имели в виду конструктор, а не оператор приведения, верно? Вы пытаетесь конвертировать ClassA в ClassBпоэтому операторы преобразования из ClassA не имеют значения в этом случае.


(*) Вы назначаете obB в obA после obAЭто конструкция, поэтому в вашем случае применим только второй пункт. Вы также можете заставить его работать, добавив оператор присваивания:

3.

class ClassA
{
public:
    ClassA& operator=(const ClassB& b)
    {
        //assign b to *this
    }
};

который будет называться в вашем случае.

Другие вопросы по тегам