#c #class #protected #derived-class
#c #класс #защищенный #производный класс
Вопрос:
У меня есть следующий фрагмент кода:
const int DATE_LENGTH = 6;
class BaseClass {
protected:
int date[DATE_LENGTH];
int year;
public:
BaseClass(){}
BaseClass(int *d) {
for (int i = 0; i < DATE_LENGTH; i ) { date[i] = d[i];}
year = 1900 date[4] * 10 date[5];
}
void printYear() {
cout << year << endl;
}
};
class DerivedClass : public BaseClass {
public:
DerivedClass() {}
void printYear() {
cout << year << endl;
}
};
int main(int argc, char *argv[]) {
int dob[] = {1, 6, 1, 0, 9, 0};
BaseClass base(dob);
base.printYear(); // prints 1990
DerivedClass derived;
derived.printYear(); // prints 1439156608
}
У меня возникли проблемы с пониманием того, почему выходные данные из printYear()
моего производного класса выводят мусор. Я упускаю что-то очень очевидное?
Будем признательны за любую помощь!
Комментарии:
1. Ваши конструкторы по умолчанию ничего не инициализируют, поэтому вы получаете все, что оказывается в памяти.
2. @T.C.: Это не совсем так, базовый подобъект действительно был инициализирован. Язык требует, чтобы это происходило. Просто была выбрана очень плохая инициализация.
3. @RetiredNinja: На самом деле это не то, что вы можете гарантировать. Это неопределенное поведение, и вы можете получить что-то из памяти, или пиццу, или потерять работу.
4. Вы можете получить пиццу из-за неопределенного поведения? Полный вперед!
5. @KerrekSB Ты прав, я требую свою пиццу! 🙂
Ответ №1:
Ваша программа имеет неопределенное поведение. Конструктор по умолчанию DerivedClass
, который вы используете, не инициализирует year
член.
Если вы хотите инициализировать базовый элемент, вы могли бы сделать это, вызвав соответствующий базовый конструктор или присвоив значение напрямую.
DerivedClass() { year = 1999; }
Комментарии:
1. Вы абсолютно уверены, что это UB и не может быть просто неопределенными значениями?
2. @Deduplicator, да,
year
неинициализирован, и для него выполняется преобразование lvalue в rvalue.
Ответ №2:
Конструктор класса по умолчанию BaseClass
BaseClass(){}
не инициализирует элементы данных date
и year
Этот конструктор по умолчанию вызывается конструктором класса по умолчанию DerivedClass
при создании производного объекта
DerivedClass derived;
Таким образом, эти элементы данных имеют произвольные значения, и ваша программа имеет неопределенное поведение.
Измените производный класс следующим образом
class DerivedClass : public BaseClass {
public:
using BaseClass::BaseClass;
DerivedClass() {}
void printYear() {
cout << year << endl;
}
};
и создать объект, производный от
DerivedClass derived( dob );
Или вместо объявления using вы можете сами явно определить конструктор в классе DerivedClass, который имеет один параметр типа int *
и вызывает соответствующий конструктор базового класса. Например
class DerivedClass : public BaseClass {
public:
DerivedClass() {}
DerivedClass( int *d ) : BaseClass( d ) {}
void printYear() {
cout << year << endl;
}
};
Ответ №3:
Другие предоставленные ответы касаются только части проблемы, отчасти потому, что сама дата никогда не определена в конструкторе по умолчанию DerivedClass ни одного из предоставленных в данный момент, а другая часть, являющаяся конструктором по умолчанию базового класса, все еще не имеет определенного значения ни для одной переменной класса (date или year). Если используется следующий код, в зависимости от того, какими должны быть дата и год по умолчанию, никаких дополнительных изменений для производного класса фактически не требуется.
#include <iostream>
using namespace std;
const int DATE_LENGTH = 6;
class BaseClass {
protected:
int date[DATE_LENGTH];
int year;
public:
BaseClass()
{
int date[] = {1, 6, 1, 0, 9, 0};
year = 1900 date[4] * 10 date[5];
}
BaseClass(int *d)
{
for (int i = 0; i < DATE_LENGTH; i ) { date[i] = d[i];}
year = 1900 date[4] * 10 date[5];
}
void printYear() {
cout << year << endl;
}
};
class DerivedClass : public BaseClass {
public:
DerivedClass() {}
void printYear() {
cout << year << endl;
}
};
int main(int argc, char *argv[])
{
int dob[] = {1, 6, 1, 0, 9, 0};
BaseClass base(dob);
base.printYear(); // prints 1990
DerivedClass derived;
derived.printYear(); // prints 1439156608
return 0;
}
Вывод приложения
1990
1990