Подтвердить что ты не робот

Зачем кому-то предоставлять пустой конструктор по умолчанию для класса?

class complex
{
  float x,y;
public:
  complex(){} //constructor with no arguments //what is use of giving such constructor
    complex(float z){x=y=z;}//constructor with 1 argument.
    complex(float real,float imag)
    {x=real;y=imag;}
    friend complex sum(complex,complex);
     friend void show(complex);
};

complex sum(complex c1,complex c2)
{
  complex c3;
  c3.x=c1.x+c2.x;
  c3.y=c1.y+c2.y;
  return (c3);
}

void show (complex c)
{
  cout<<c.x<<"+j"<<c.y<<"\n";
}
int main()
{
  complex p,q,r;
  p=complex(2.5,3.9);
  q=complex(1.6,2.5);
  r=sum(p,q);

  cout<<"p=";show(p);
  cout<<"q=";show(q);
  cout<<"r=";show(r);
  return 0;
}
4b9b3361

Ответ 1

Когда вы объявляете класс без каких-либо конструкторов, компилятор предоставляет конструктор по умолчанию (по запросу), который по умолчанию инициализирует члены. (Обратите внимание, что инициализация по умолчанию для встроенных модулей, таких как float ничего не делает). Однако, как только вы определяете какой-либо конструктор для класса, конструктор по умолчанию больше не предоставляется автоматически. Следовательно, вы должны определить свой собственный конструктор по умолчанию, если вы все еще хотите его.

Ответ 2

Это скопированная и исправленная версия @user470379 answer

Рассмотрим пустой класс:

class complex
{
    float x,y;
};

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

class complex
{
    float x,y;
public:
    complex(); //Compiler generated functions
    complex(const complex&);
    complex& operator=(const complex&);
    ~complex();
};

Теперь вы берете свой сложный класс и добавляете свой конструктор с помощью float. Когда вы это сделаете, вы сообщите С++, что вы не хотите, чтобы предоставленный компилятором конструктор по умолчанию:

class complex
{
    float x,y;
public:
    // complex(); //No longer generated
    //Don't forget explicit here unless you want implicit conversions
    //from `float`
    explicit complex(float z) {x=y=z;} //User defined constructor
    /////////////////////////////////////////////////////////
    //Compiler generated functions
    complex(const complex&);  //Note copy constructor and copy assignment
                              //operator are still generated.
    complex& operator=(const complex&);
    ~complex();
};

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

int main()
{
    complex c; //ERROR! No default constructor available.
    complex g(4.2f); //Ok; float parameter specified.
}

Если вы хотите, чтобы ваш пользователь мог просто построить complex без предоставления параметра float, вы должны явно создать конструктор:

class complex
{
    float x,y;
public:
    complex() {} //Allow default construction of `complex` objects.
    //Don't forget explicit here unless you want implicit conversions
    //from `float`
    explicit complex(float z) {x=y=z;}
    ////////////////////////////////////////////////////////
    complex(const complex&);  //Compiler generated functions
    complex& operator=(const complex&);
    ~complex();
};

Теперь пользователь может по умолчанию построить объект complex в любом месте.

Ответ 3

Поскольку некоторые программисты не повысили свои привычки до современных стандартов.

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

В современном С++ едва ли есть хорошая причина не объявлять и не инициализировать в том же самом заявлении.

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

Ответ 4

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

Иногда вы можете захотеть, чтобы объекты (или были вынуждены стандартным требованием) имели "нулевое" состояние, доступное только конструктору по умолчанию. Затем вам нужно написать безопасные идиомы bool, использовать умные указатели и идиомы pimpl и т.д. Это может быть хорошо или нет.

Я согласен, не стоит добавлять сложность нулевых состояний (и ошибок, которые они могут вызвать) к объектам, которые им не нужны, но иногда вы вынуждены.

Для записи сложные классы должны выглядеть так:

struct complex
{
    // Allow default initialization, and standard embedding
    // of real numbers in complex numbers
    complex(float real = 0., float imag = 0.) 
        : real(real), imag(imag) 
    {}

    float real, imag; // no need for privacy here
};

// Operators are defined outside the class
complex operator+(complex x, complex y) 
{
    return complex(x.real + y.real, x.imag + y.imag);
}

// etc

std::ostream& operator<<(std::ostream& os, complex x)
{
    return os << x.real << " + i" << x.imag;
}

Обратите внимание, что поскольку complex является типом POD, вы даже можете сделать complex x = { 2., 3. }; и инициализировать их нулевым для вас в статических массивах.

Ответ 5

Работа с стандартной библиотекой С++ обычно требует, чтобы ваши классы имели конструктор no-arg (например: vector<complex> vc(6);).

Создание массивов, распределенных по стекам (complex arcmpl[20];) или динамически распределенных (complex * dynarcmplx = new complex[n];), а также вызовы конструкторов no-arg.

Как уже было сказано, если вы определяете какой-либо конструктор для своего класса, у вас больше нет (компилятор сгенерированный no-arg) "конструктор по умолчанию", и в этом случае, если вы хотите написать что-то вроде упомянутого выше, вы должны предоставить собственный конструктор no-arg.

Ответ 6

Предоставление пустого конструктора по умолчанию ( private) необходимо в тех случаях, когда вам не нужен объект класса во всей программе.

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

class test1
{
public:
int a;
};
int main()
{
test1 var; //compiles without an error.
}

Однако, если вы хотите, чтобы кто-то не смог создать объект класса, вы можете добавить пустой конструктор в качестве private member. Например,

class test2
{
test2(){}
public:
int a;
};

int main()
{
test2 var; // This will give an error
}

abc.cpp: внутри функции: main(): abc.cpp: 10: 9: ошибка: тест2 :: test2() - является закрытой в этом контексте test2 var; // Это выдаст ошибку ^ ~~ abc.cpp: 3: 3: note: здесь объявлено приватное test2() {} ^ ~~~~

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