Конструктор классов C++ по умолчанию
-
19-08-2019 - |
Вопрос
Ранее я спрашивал, почему это считается плохим:
class Example
{
public:
Example(void);
~Example(void);
void f() {}
}
int main(void)
{
Example ex(); // <<<<<< what is it called to call it like this?
return(0);
}
Теперь я понимаю, что вместо этого создается прототип функции, который возвращает пример типа.Хотя я все еще не понимаю, почему это будет работать в g ++ и MS VC ++.
Мой следующий вопрос заключается в использовании приведенного выше, будет ли этот вызов действительным?
int main(void)
{
Example *e = new Example();
return(0);
}
?В чем разница между этим и простым вызовом Example e()???Как будто я знаю, что это прототип функции, но, похоже, возможно, некоторые компиляторы прощают это и позволяют ему вызывать конструктор по умолчанию?Я тоже это пробовал:
class Example
{
private:
Example();
public:
~Example();
};
int main(void)
{
Example e1(); // this works
Example *e1 = new Example(); // this doesn't
return(0);
}
Так что я немного сбит с толку: ( Извините, если об этом спрашивали миллион раз.
Решение
это вопрос будет полезно понять это поведение
Другие советы
Это просто, Дэниел:
Example *e = new Example();
Это не похоже на функцию под названием "Example", не так ли?Функция имеет возвращаемое значение, имя и параметры.Как бы к этому подошло вышесказанное?
Пример e1();// это работает
Да, потому что вы не создаете никакого экземпляра Example
где угодно.Вы просто сообщаете коду, что где-то в окружающем пространстве имен есть функция, определенная, и вы, возможно, хотите вызвать эту функцию.Да, это правда, что для того, чтобы вернуть объект Example, должен быть создан экземпляр.Но это не означает, что в этот момент создается экземпляр.Скорее, экземпляр создается в функции, когда вы ее вызываете.
Хм...Хорошо, это:
Пример e1();
Не работает.Вы можете подумать, что это так, или какой-то компилятор принимает это, но он не создает экземпляр Example с именем e1, он просто объявляет прототип функции.Снимите скобки, и он сделает то, что вы хотите.
Это:
Пример * e1 = новый пример();
Не будет работать, потому что конструктор является закрытым.Если вы сделаете конструктор общедоступным, он создаст объект в куче, и e1 будет указателем на этот объект.Вам нужно будет удалить объект, когда вы закончите с ним.
Для первого вопроса о том, будет ли "новый пример ()" действительным.Да, это совершенно легальный код на C ++.Хотя, чтобы быть полностью корректным, вам нужно будет удалить объект перед возвратом из main(), иначе это приведет к утечке памяти.
Пример:
int main(void)
{
Example *e = new Example();
delete e;
return(0);
}
Что касается последнего вопроса.Строка "Example e1();" является допустимой, поскольку в ней объявляется прототип функции.На самом деле это не приводит к выполнению машинного кода (ну, может быть, пространство стека).Это просто говорит о том, что существует прототип функции без аргументов, возвращающий тип Example .
Однако вторая строка определенно потерпит неудачу.На этом этапе вы пытаетесь фактически выполнить конструктор, например.Это незаконно, поскольку доступность функции является частной, отсюда и ошибка компилятора.
Я думаю, вам следует различать "это анализирует", "это компилирует", "это связывает" и "это работает", и попробуйте сами мыслить как синтаксический анализатор / компилятор / компоновщик C ++, чтобы увидеть, что первый пример
Example e1(); // function prototype
выглядит как объявление функции.Синтаксический анализатор будет поймите это таким образом, поэтому вы не можете вызвать, напримерфункция - член на e1
.Компилятор сгенерирует символ, ссылающийся на некоторую функцию (он пока не видит), но поскольку функция нигде не используется, он не будет жаловаться.Если вы добавите этот код, он будет:
e1.f();// since e1 is a function, it has no member 'f' => compiler error
( в качестве примечания:этот код также будет скомпилирован:
int a_function_prototype(int); // another prototype.
e1(); // should work!
a_function_prototype(5);
но после того, как компилятор завершит работу, компоновщик начнет искать фактические тела функций и не найдет ни одного.)
Теперь , поскольку линия
Example* e = new Example();
содержит ключевое слово new
компилятор распознает, и он знает, что это может быть найдено только при выделении + конструировании нового объекта, он сгенерирует код для этого.