Инициализация ссылочного элемента: причина разного синтаксиса - PullRequest
1 голос
/ 02 апреля 2020

У меня есть два класса, один из которых имеет объект другого в качестве эталонного члена:

class myClass{
public:
    myClass() { };
};

class mySecondClass {
public:
    mySecondClass(myClass& reference)
    {
        myClassReference = reference; //doesn't get accepted by the compiler
    };

    myClass& myObjectReference;
};

Я обнаружил (благодаря Передача по ссылке на конструктор ) , что mySecondClass(myClass& reference) : myObjectReference(reference){}; делает работу.

Но почему я не могу использовать myObjectReference = reference;?

Ответы [ 2 ]

3 голосов
/ 02 апреля 2020

Это потому, что { myClassReference = reference; } рассматривается как присвоение чему-то, что должно быть уже инициализировано.

Список инициализации члена : member1{value1}, member2{value2}... предназначен для предоставления начального значения (ничто не должно быть действительным до).

Для указанного c случая ссылки это та же ситуация, что и

int i=4;
int &r=i; // the reference is initialised (alias for i)
r=5;      // the reference itself is not changed but
          //   the referenced object (i) is assigned
2 голосов
/ 02 апреля 2020

В конструкторе

mySecondClass(myClass& reference)
{
    myClassReference = reference; //doesn't get accepted by the compiler
};

используется ссылка myClassReference, которая должна быть инициализирована при ее создании. Однако переменная не была инициализирована. Используется оператор копирования.

В этом конструкторе

mySecondClass(myClass& reference) : myObjectReference(reference){}
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

ссылка создается и инициализируется в списке mem-initializer.

Чтобы сделать его более понятным рассмотрим следующую демонстрационную программу.

#include <iostream>

struct Int
{
    Int() { std::cout << "Int()\n"; }
    Int( int x ) : x( x ) { std::cout << "Int( " << x << " )\n"; }
    Int & operator =( int x )
    {
        std::cout << "Int & operator =( " << x << " )\n";
        this->x = x;

        return *this;
    }

    int x;
};

struct A
{
    A( int x )
    {
        this->value = x;
    }
    Int value;
};

struct B
{
    B( int x ) : value( x ) {}
    Int value;
};

int main() 
{
    A a( 10 );

    std::cout << '\n';

    B b( 10 );

    return 0;
}

Его вывод

Int()
Int & operator =( 10 )

Int( 10 )

То есть, когда тело конструктора A получает элемент управления, член данных уже был создан с использованием конструктора по умолчанию класс Int. В теле конструктора используется оператор присваивания.

В противоположность конструктору класса A конструктор класса B создал член данных в списке mem-inkitializer, используя конструктор класса Int. с параметром.

Итак, теперь представьте, что вы используете ссылку в классе A. Затем она «инициализируется по умолчанию», то есть фактически не инициализируется ни одним допустимым объектом, на который ссылается оболочка. Таким образом, в теле конструктора вы пытаетесь присвоить значение недопустимой ссылке, которая нигде не ссылается. Таким образом, компилятор выдает ошибку.

...