C++ по сравнению с конструкторами Java

Некоторый более старый веб-хостинг и серверы DNS на самом деле имеют проблемы при парсинге подчеркиваний для URL, так, чтобы мог играть роль в соглашениях как они.

6
задан jalf 8 December 2009 в 10:16
поделиться

15 ответов

Давая интерпретацию, у меня есть предположение, почему автор говорит это для Java, не обращая внимания на какие-либо угловые случаи, которые, как мне кажется, не решают проблему: вы могли бы подумать, например, что POD не являются объектами.

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

class A {
   int x;
public:
   A() : X(0) {}
   virtual void f() { x=x+1; }
   virtual int getX() { return x; }
};

int main() {
   A *a = (A *)malloc(sizeof(A));
   cout << a->getX();
   free(a);
}

Это вполне приемлемая программа на C ++, в которой используется непроверенная форма приведения типов, чтобы избежать вызова конструктора. В этом случае x не инициализируется, поэтому мы можем ожидать непредсказуемого поведения.

Однако могут быть и другие случаи, когда Java также не может применить это правило, упоминание сериализованного объекта совершенно разумно и правильно,

1
ответ дан 8 December 2019 в 02:26
поделиться

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

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

Как и другие плакаты упомянуто, если ваш класс относится к типу POD, есть случаи, когда ваш объект останется неинициализированным. Но это не потому, что компилятор «не вызвал конструктор». Причина в том, что тип не имеет конструктора (или имеет конструктор, который ничего не делает) и обрабатывается несколько особым образом. Но опять же, типы POD не существуют в Java, так что их нельзя сравнивать.

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

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

14
ответ дан 8 December 2019 в 02:26
поделиться

То, что он имеет в виду, в Java: конструктор суперкласса вызывается всегда. Это делается путем вызова super (...), и если вы опустите этот компилятор, он вставит его за вас. Единственное исключение - один конструктор вызывает другой конструктор. В этом случае другой конструктор должен вызвать super (...).

Эта автоматическая вставка кода компилятором на самом деле странная. И если у вас нет вызова super (...) и родительский класс не имеет конструктора без параметра, это приведет к ошибке компиляции. (Странно иметь ошибку компиляции для чего-то, что автоматически вставляется.)

C ++ не сделает эту автоматическую вставку за вас.

а родительский класс не имеет конструктора без параметра, это приведет к ошибке компиляции. (Странно иметь ошибку компиляции для чего-то, что автоматически вставляется.)

C ++ не будет выполнять эту автоматическую вставку за вас.

а родительский класс не имеет конструктора без параметра, это приведет к ошибке компиляции. (Странно иметь ошибку компиляции для чего-то, что автоматически вставляется.)

C ++ не сделает эту автоматическую вставку за вас.

-1
ответ дан 8 December 2019 в 02:26
поделиться

Кажется, это сводится к определению термина «объект», так что утверждение является тавтологией. В частности, что касается Java, он, по всей видимости, определяет «объект» как экземпляр класса. Что касается C ++, он (по-видимому) использует более широкое определение объекта, которое включает такие вещи, как примитивные типы, у которых даже нет конструкторов.

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

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

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

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

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

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

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

0
ответ дан 8 December 2019 в 02:26
поделиться

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

можно увидеть в следующем фрагменте кода. я еще не видел ни одного общего случая, когда конструктор не вызывается, но тогда можно увидеть так много:)

include

using namespace std;

class Object

{

public :

Object ();

~ Object ();

};

встроенный Object :: Object ()

{

cout << "Конструктор \ n";

};

встроенный Object :: ~ Object ()

{

cout << "Деструктор \ n";

};

int main ()

{

буфер символов [2 * sizeof (Object)];

Object * obj = new (buffer) Object; // размещение нового, 1-го объекта

new (buffer + sizeof (Object)) Object; // размещение нового, 2-го объекта

// удаление obj; // НЕ ДЕЛАЙТЕ ЭТОГО

obj [0]. ~ Object (); // уничтожаем 1-й объект

obj [1]. ~ Object (); // уничтожаем 2-й объект

}

0
ответ дан 8 December 2019 в 02:26
поделиться

Попытка прояснить ситуацию с C ++. Множество неточных утверждений в ответах.

В C ++ POD и класс ведут себя одинаково. ВСЕГДА вызывается конструктор. Для POD конструктор по умолчанию ничего не делает: он не инициализирует значение. Но было бы ошибкой сказать, что конструктор не вызывается.

Даже при наследовании вызываются конструкторы.

class A {
  public: A() {}
};

class B: public A {
  public: B() {}   // Even if not explicitely stated, class A constructor WILL be called!
};
0
ответ дан 8 December 2019 в 02:26
поделиться

Только когда вы перегружаете новую операторную функцию, конструктор не вызывается (раньше он избегайте вызова конструктора), иначе в стандарте конструктор вызывается при создании объекта.

void * operator new ( size_t size )
{

     void *p = malloc(size);

     if(p)
       return p; 
     else
        cout<<endl<<"mem alloc failed";
}

class X
{   

   int X;

};

int main()
{

       X *pX;

       pX = reinterpret_cast<X *>(operator new(sizeof(X)*5)); // no ctor called

}
1
ответ дан 8 December 2019 в 02:26
поделиться

Насколько я помню, Мейерс в своем «Эффективном C ++» говорит, что объект создается ТОЛЬКО, когда поток управления достигает конца его конструктора. В противном случае это не объект. Всякий раз, когда вы хотите неправильно использовать некоторую необработанную память для реального объекта, вы можете сделать это:

class SomeClass
{
   int Foo, int Bar;
};

SomeClass* createButNotConstruct()
{
   char * ptrMem = new char[ sizeof(SomeClass) ];
   return reinterpret_cast<SomeClass*>(ptrMem);
}

Здесь вы не столкнетесь ни с какими конструкторами, но вы можете подумать, что вы работаете с недавно созданным объектом (и отлично проводите время, занимаясь отладкой it);

0
ответ дан 8 December 2019 в 02:26
поделиться

Java может фактически выделять объекты без (!) вызова какого-либо конструктора.

Если вы просмотрите источники ObjectInputStream , вы обнаружите, что это выделяет десериализованные объекты без вызова какого-либо конструктора.

Метод, позволяющий это сделать, не является частью общедоступного API, он находится в пакете sun. * . Однако, пожалуйста, не говорите мне, что это не часть языка из-за этого. Что вы можете сделать с общедоступным API, так это собрать поток байтов десериализованного объекта, прочитать его, и вот вы перейдете к экземпляру объекта, конструктор которого никогда не вызывался!

2
ответ дан 8 December 2019 в 02:26
поделиться

В C ++ при создании экземпляра объекта должен быть вызван конструктор этого класса.

2
ответ дан 8 December 2019 в 02:26
поделиться

Конструкторы Java могут вызывать другой конструктор того же класса. В C ++ это невозможно. http://www.parashift.com/c++-faq-lite/ctors.html

POD (простые старые типы данных) не инициализируются с помощью конструкторов в C ++:

struct SimpleClass {
    int m_nNumber;
    double m_fAnother;
};

SimpleClass simpleobj = { 0 }; 
SimpleClass simpleobj2 = { 1, 0.5 }; 

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

  • Неконстантный объект POD, объявленный без инициализатора, имеет «неопределенное начальное значение».
  • Инициализация объекта POD по умолчанию - это нулевая инициализация. ( http://www.fnal.gov/docs/working-groups/fpcltf/Pkg/ISOcxx/doc/POD.html )

Если, однако, SimpleClass сам определил конструктор, SimpleClass не больше не будет POD, и всегда будет вызываться один из конструкторов.

3
ответ дан 8 December 2019 в 02:26
поделиться

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

struct X {
   int x;
};
int main() {
   X x;        // implicit default constructor not called
               //    No guarantee in the value of x.x
   X x1 = X(); // creates a temporary, calls its default constructor
               //    and copies that into x1. x1.x is guaranteed to be 0
}

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

Для дальнейшего решения проблемы:

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

Да, с типами POD вы можете создавать экземпляры объектов, и никакой конструктор не будет вызываться. Причина в том, что

Это, конечно, сделано для совместимости с C.

(как комментирует Нил)

Я думаю, что это происходит, когда происходит наследование, но я не могу найти пример для этого случая.

Это не имеет ничего общего с наследованием, а связано с типом создаваемого объекта.

2
ответ дан 8 December 2019 в 02:26
поделиться

Для типов C ++, которые объявляют конструкторы, невозможно создать экземпляры этих типов без использования конструктора. Например:

class A {
   public:
      A( int x ) : n( x ) {}
  private:
      int n;
};

невозможно создать instancev для A без использования конструктора A (int), кроме как путем копирования, которое в этом случае будет использовать синтезированный конструктор копирования. В любом случае необходимо использовать конструктор.

4
ответ дан 8 December 2019 в 02:26
поделиться

В Java есть два случая (я больше не знаю), в которых класс может быть создан без вызова его конструктора, что не приведет к взлому в C или подобном:

  • Во время десериализации у сериализуемых классов не вызывается их конструктор. Конструктор без аргументов самого производного несериализуемого класса вызывается механизмом сериализации (в реализации Sun через непроверяемый байт-код).
  • Когда используется злой Object.clone .

Таким образом, утверждение, что конструкторы всегда вызываются в Java, неверно.

9
ответ дан 8 December 2019 в 02:26
поделиться

В Java бывают ситуации, когда конструктор не вызывается .

Например, когда класс десериализуется, конструктор по умолчанию для первого несериализуемого класса в иерархии типов будет вызываться, но не конструктор текущего класса. Также Object.clone избегает вызова конструктора. Вы также можете сгенерировать байт-код и сделать это самостоятельно.

Чтобы понять, как это возможно, даже без магии нативного кода внутри JRE, просто взгляните на байт-код Java. Когда ключевое слово new используется в коде Java, из него генерируются две инструкции байт-кода - сначала экземпляр выделяется с помощью инструкции new , а затем вызывается конструктор с помощью вызывает специальную инструкцию .

Если вы генерируете свой собственный байт-код (например, с помощью ASM), можно изменить инструкцию invokespecial для вызова конструктора одного из конструкторов суперклассов фактического типа (например, java. lang.Object ) или даже полностью отказаться от вызова конструктора. JVM не будет жаловаться на это. (Проверка байт-кода проверяет только то, что каждый конструктор вызывает конструктор своего суперкласса, но вызывающий конструктор не проверяется, какой конструктор вызывается после new .)

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

s конструктора суперклассов (например, java.lang.Object ) или даже полностью пропустите вызов конструктора. JVM не будет жаловаться на это. (Проверка байт-кода проверяет только то, что каждый конструктор вызывает конструктор своего суперкласса, но вызывающий конструктор не проверяется, какой конструктор вызывается после new .)

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

s конструктор суперклассов (например, java.lang.Object ) или даже полностью пропустите вызов конструктора. JVM не будет жаловаться на это. (Проверка байт-кода проверяет только то, что каждый конструктор вызывает конструктор своего суперкласса, но вызывающий конструктор не проверяется, какой конструктор вызывается после new .)

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

0
ответ дан 8 December 2019 в 02:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: