конструкция объекта: параметр по умолчанию против делегирования

Рассмотрим следующий код, в котором я пытаюсь ввести конструктор по умолчанию, а также параметризованный конструктор для class A. Этот способ был представлен в недавних улучшениях С++.

class A  {
    private:
        unsigned int count;

    public:
        A(int new_c) : count(new_c) {}
        A() : A(10) {}
};

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

class A  {
    private:
        unsigned int count;

    public:
        A(int new_c = 5) : count(new_c) {}
};

Есть ли какое-либо преимущество использования 1-го метода по сравнению со 2-м, кроме следования современным соглашениям?


person Abhinav Gauniyal    schedule 01.07.2015    source источник
comment
Для такого упрощенного варианта использования нет никакой реальной разницы.   -  person T.C.    schedule 01.07.2015
comment
Поскольку A() полностью независим от A(int), у него есть собственное тело, в котором после вызова A(int) может быть сделано что-то конкретное.   -  person Jacques de Hooge    schedule 01.07.2015
comment
@Т.С. Можете ли вы указать какой-либо другой сложный вариант использования, который может показать какое-либо преимущество/различие.   -  person Abhinav Gauniyal    schedule 01.07.2015


Ответы (4)


Хотя технически разницы нет, идея создания конструкторов переадресации была другой. Представьте себе следующий класс:

class sample {
    complexType member;
    bool createdWithInt;
public:
    sample() : member(5), createdWithInt(false) {
       /* code ... */
    }
    sample(int param) : sample() {
       createdWithInt = true;
       /* other code */
    }
};

Так что этот класс трудно реализовать с параметрами по умолчанию: его поведение не зависит от значения параметра, а зависит от его наличия.

Можно попытаться реализовать это с помощью вспомогательной функции void creator(), которая выполняет бит code ... из конструктора без аргументов. Однако это будет означать дублирование списка инициализации (или отказ от принципа RAII, если он инициализируется изнутри creator()).

Примечание. createdWithInt можно было бы инициализировать из списка инициализации, если был добавлен другой конструктор, который принимает логическое значение, и оба текущих конструктора перенаправляются к этому. Ради примера это было опущено.

person ted    schedule 01.07.2015
comment
... Конечно, на самом деле этот класс является кандидатом на полиморфную частную реализацию... ;) - person Richard Hodges; 01.07.2015

Функционально разницы нет. Знайте, что есть еще один вариант, доступный с нестатической инициализацией члена (начиная с C++11):

class A  {
    private:
        unsigned int count = 10;

    public:
        A() = default;
        A(int new_c) : count(new_c) {}
};
person Cory Kramer    schedule 01.07.2015

В случае, как в вашем примере, нет преимущества (я бы даже выбрал 2-й вариант как более понятный в таком примере)

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

Например

struct Point3d
{
   Point3d(int x, int y, int z);
   Point3d(Point2d p) : Point3d(p.x, p.y, 0) {}
}
person Hcorg    schedule 01.07.2015

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

class A  {
    private:
        unsigned int count;
        int other;
        float otherfloat;


    public:
        A( unsigned int count, int other, float otherfloat ) : count( count), other( other ), otherfloat( otherfloat ) {}
        A(int new_c) : A(new_c, 0, 0.0 ) {}
        A() : A(10) {}
};
person Robert Wadowski    schedule 01.07.2015