Конструктор C ++ по умолчанию - PullRequest
1 голос
/ 19 января 2009

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

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

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

Ответы [ 5 ]

5 голосов
/ 19 января 2009

Это легко, Даниэль:

Example *e = new Example();

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

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

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

1 голос
/ 19 января 2009

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

Пример:

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

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

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

1 голос
/ 19 января 2009

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

Пример e1 ();

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

Это:

Example * e1 = new Example ();

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

1 голос
/ 19 января 2009

этот вопрос будет полезно понять это поведение

0 голосов
/ 19 января 2009

Я думаю, что вы должны различать «этот синтаксический анализ», «этот компилятор», «этот линк» и «это работает», и попытаться думать как синтаксический анализатор / компилятор / компоновщик C ++ самостоятельно, чтобы увидеть, что первый пример

Example e1(); // function prototype

выглядит как объявление функции. Синтаксический анализатор поймет это таким образом, поэтому вы не можете вызвать, например, функция-член на e1. Компилятор сгенерирует символ, относящийся к некоторой функции (он пока не видит), но, поскольку функция нигде не используется, он не будет жаловаться. Если вы добавите этот код, он будет:

e1.f();// since e1 is a function, it has no member 'f' => compiler error

(в качестве sidenote: этот код также будет компилироваться:

int a_function_prototype(int); // another prototype.
e1(); // should work!
a_function_prototype(5);

но после завершения работы компилятора компоновщик начнет поиск реальных тел функций и не найдет их.)

Теперь, так как линия

Example* e = new Example();

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

...