Конструкторы C++ не имеют возвращаемого типа. Почему именно?

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

некоторые говорят, что нет возврата, потому что нет способа вернуться - синтаксис запрещает это - да, это имеет смысл, но я считаю, что все функции должны что-то вернуть, нет? Другие говорят, что конструктор возвращает только что созданный объект, который, кажется, делает sense, так как оператор присваивания используется в конструкторе. У других есть и другие интересные объяснения.

8 ответов


конструкторы не вызываются как другие функции, поэтому они не возвращаются как другие функции. Они выполняются как побочный эффект определенных конструкций (cast,new, определение переменной, ctor-инициализатор-список, pass-by-value, return-by-value).


конструктор не указывает возвращаемый тип, потому что он был бы избыточным: нет другого типа, кроме создаваемого, который конструктор мог бы потенциально "вернуть". Я помещаю "return" в кавычки, потому что технически конструкторы ничего не возвращают: когда они вызываются в статическом контексте, они инициализируют экземпляр на месте; когда они вызываются в динамическом контексте, это оператор new Это возвращает что-то, а не конструктор.


конструктор строит на месте, ему не нужно ничего возвращать.

Я считаю, что все функции должны возвращать что-то

void?


предполагая, что конструкторы могут что-то вернуть, это имеет проблемные последствия для следующего вызова функции:

class Object{ 
    public: 
        bool Object(){ ... };   
        ...
}      

SomeFun(Object obj){ ... } 

SomeFun(Object());   
// Ha! SomeFun jokes on an error about a non-Object argument(of type bool), returned  
// by the anonymous temporary Object()

предотвращение возврата функций конструктора облегчает использование анонимных временных файлов, а также многих других функций C++. Без такого правила безобидные утверждения могут стать двусмысленными:

Object obj(Object()); 
// How does the variable obj decide which constructor to call,  
// based on its argument type?  
// 
// Does it call: bool Object::Object(Object&) or  
//                    Object::Object(bool)(if it exists)? 

возможность конструкторов возвращать значение, усложняет создание объектов-имеющих один однозначный тип, имя класса при отсутствии произвольных возвращаемых значений позволяет избежать таких проблем.

могут ли читатели предложить дополнительные примеры, когда идиомы C++ затрудняются отсутствием такого правила?


но я считаю, что все функции должны что-то возвращать, нет?

нет. Что значит возвращать значение из функции? Ну, ABI для реализации будет указывать, что для некоторого возвращаемого типа функция будет устанавливать определенные регистры или некоторую память с некоторым смещением от указателя стека к значению, которое "возвращается" функцией.

очевидно, что регистры и память существуют и содержат данные после конструктора или функции void вызывается, но язык говорит, что эти функции ничего не возвращают, и поэтому ABI не указывает, какие регистры или память искать, чтобы найти возвращаемое значение. Код не может установить возвращаемое значение, и вызывающий код может получить любое возвращаемое значение.

Так что нет, функции не должны ничего возвращать.


что конструкторам не хватает возвращаемого типа -- даже void -- означает, что вы не можете вызвать конструктор из кода C++. В этом-то все и дело. Вызов конструктора не имеет смысла. Запрещение вызова конструктора исключает саму возможность ошибки этого типа пользователя.

редактировать

Барнс прав в том, что конечная причина, по которой вы не можете вызывать конструкторы, заключается в том, что у них нет имени. (И даже это игнорирует, что ты может вызывать конструктор косвенно через размещение new.)

снова попытка:

вы не можете вызывать конструкторы из кода C++, потому что конструкторы не имеют имени. Создание конструкторов без возвращаемого типа подчеркивает программисту, что конструкторы-это совсем другой вид функции, чем другие функции. То, что конструктор действительно возвращает, если он возвращает что-либо, зависит от поставщика.


конструкторы, возможно, плохое имя для него. Это практически инициализатор для предварительно построенных объектов. Самый простой способ проиллюстрировать это-псевдо-пример для эквивалентной конструкции без использования конструкторов C++.

С конструкторами

struct X {
    int a;
    X() {
      a = -5;
    }
};

int main() {
    X* x1 = new X(); // X created as a "reference object".
    X  x2;           // X created as a "value object" on the stack.
    return x1->a - x2.a;
}

без конструкторов

struct X {
    int a;
    void initialize() {
        a = -5;
    }
    static X* create() {
        X* res = (X*)malloc(sizeof(X));
        res->initialize();
        return res;
    }
};

int main() {
    X* x1 = X::create(); // New constructed heap-allocated X
    X  x2;               // Stack-allocated X
    x2.initialize();     // Manually initialized
    return x1->a - x2.a;
}

теперь, если Вы себе это представляете X::initialize во втором примере должны были быть возвращены, сказать bool указывая на успех или неудачу, у вас будет проблема. В main(), невнимательный программист может получить X это неправильно инициализировано, что приводит к неопределенному поведению (обычно трудно отлаживаемый сбой, который может не быть обнаружен до производства).

это одна из основных причин, почему конструкторы сделали специальное. Единственные два способа выхода из конструктора - это обычное завершение или исключение, которое должны затем обрабатывается вызывающим абонентом (или передается вверх по стеку). В любом случае, вы предотвратите попадание в неинициализированные объекты.

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


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