Конструктор по умолчанию для классов C ++

Ранее я спрашивал, почему это считается плохим:

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);
}

Теперь я понимаю, что вместо этого создается прототип функции, которая возвращает тип Example. Я до сих пор не понимаю, почему это работает в 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);
}

Так что я немного запутался :( Извините, если об этом спрашивали миллион раз.


person Daniel    schedule 19.01.2009    source источник
comment
это связано с распределением памяти в стеке, а не с конструктором по умолчанию   -  person yesraaj    schedule 19.01.2009


Ответы (5)


этот вопрос поможет понять такое поведение.

person yesraaj    schedule 19.01.2009
comment
Привет спасибо. Так что я думаю, это неприятная проблема с синтаксическим анализом. Да, потрясающе, я всегда использовал Example e (); и никогда не сталкивался с проблемой MS VC ++ (VS 2005) и gnu g ++ (не помню версию). Так что для меня это все в новинку ... думаю, ты узнаешь что-то новое каждый день. - person Daniel; 19.01.2009

Это просто, Даниэль:

Example *e = new Example();

Это не похоже на функцию под названием «Пример», не так ли? Функция имеет возвращаемое значение, имя и параметры. Как все вышеперечисленное подходит к этому?

Пример e1 (); // это работает

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

person Johannes Schaub - litb    schedule 19.01.2009
comment
Пример e1 (); тоже не имеет возвращаемого значения, но все равно выглядит как функция. Я скорее скажу, что знак = и ключевое слово new однозначно очищают его от вызова конструктора выделения +, результат которого сохраняется в только что объявленной переменной-указателе. - person xtofl; 19.01.2009
comment
xtoly. Пример e1 (); имеет возвращаемый тип, это Пример :) - person Johannes Schaub - litb; 19.01.2009
comment
Прошло почти 5 лет ... и я ищу немного другую тему, но это отличный простой ответ на этот вопрос; однако я продолжал читать это как сарказм, и мне потребовалось некоторое время, чтобы понять. Для других, которые могут быть медленными, как я :) Первая строка создает указатель на объект Example и вызывает конструктор по умолчанию, а вторая строка является прототипом повседневной функции. - person Jess; 24.10.2013

Хм ... ОК, это:

Пример e1 ();

Не работает. Вы можете подумать, что это так, или какой-то компилятор принимает это, но он не создает экземпляр Example с именем e1, он просто объявляет прототип функции. Снимите скобки, и он сделает то, что вы хотите.

Этот:

Пример * e1 = новый Пример ();

Не будет работать, потому что конструктор частный. Если вы сделаете конструктор общедоступным, он создаст объект в куче, а e1 будет указателем на этот объект. Вам нужно будет удалить объект, когда вы закончите с ним.

person Kazade    schedule 19.01.2009

Для первого вопроса о том, будет ли действителен «новый пример ()». Да, это совершенно законный код C ++. Хотя, чтобы быть полностью верным, вам нужно будет удалить объект перед возвратом из main (), иначе это приведет к утечке памяти.

Пример:

int main(void)
{
 Example *e = new Example();
 delete e;
 return(0);
}

По последнему вопросу. Строка «Пример e1 ();» действителен, потому что объявляет прототип функции. Это на самом деле не приводит к выполнению машинного кода (ну, возможно, пространство стека). Это просто означает, что существует прототип функции без аргументов, возвращающий тип Example.

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

person JaredPar    schedule 19.01.2009

Я думаю, вам следует различать 'this parses', 'this compiles', 'this links' и 'this works' и пытаться думать как парсер / компилятор / компоновщик 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, распознаваемое компилятором, и если он знает, что его можно найти только при выделении + построении нового объекта, он сгенерирует для этого код.

person xtofl    schedule 19.01.2009