При решении задач в популярном учебнике я получил ошибку при использовании функции-члена в структуре:
…/s09-04-02.cpp:30: неопределенная ссылка на `Date::Date(int, int, int)’
// s09-04-02.cpp простая дата
#include <iostream>
struct Date {
int y, m, d; // год
Date(int y, int m, int d); // объявление конструктора
void add_day(int n); // объявление добавления n дней
int month() {return m;}; // определение возвращения месяца
int day() {return d;}; // определение возвращения дня
int year() {return y;}; // определение возвращения года
};
int main() {
Date birthday {1970,12,30};
std::cout<<birthday.year()<<"\n";
std::cout<<birthday.month()<<"\n";
std::cout<<birthday.day()<<"\n";
}
g++ -g -o s09-04-02 s09-04-02.cpp
/usr/bin/ld: /tmp/ccXgSexK.o: in function `main':
/home/c++/Stroustrup/PPandP2nd/Ch09Classes/s09-04-02.cpp:13: неопределенная ссылка на `Date::Date(int, int, int)'
collect2: ошибка: ld вернул статус выхода 1
make: *** [Makefile:5: d09-04-02] Ошибка 1
Показалось очевидным, что функция с соответствующим именем будет определена. Почему она отсутствовала, когда компоновщик искал ее?
Посмотрел несколько статей на Stack Exchange и …
Включая эту очень полную (и длинную) статью
что такое неопределенная ссылка, ошибка неразрешенного внешнего символа и как исправить
Вы просто объявили конструктор Date
, поэтому компилятор знает, что он существует. Но вы не определили (реализовали) его тело, поэтому компоновщик не может на него ссылаться в том месте, где вы его вызываете.
Вам нужно добавить это определение, например:
struct Date {
int y, m, d;
Date(int y, int m, int d) : y(y), m(m), d(d) {} // объявление & определение конструктора
...
};
Или:
struct Date {
int y, m, d;
Date(int y, int m, int d); // объявление конструктора
...
};
// Определение конструктора
Date::Date(int y, int m, int d)
: y(y), m(m), d(d)
{
}
(у вас такая же проблема и с add_day()
)
Ответ
Ошибка "undefined reference to Date::Date(int, int, int)
" возникает из-за того, что компилятор видит объявление конструктора класса Date
, но не находит его реализацию. В C++ объявление функции позволяет компилятору знать о ее существовании, но без определения (реализации) функции компилятор не может связать вызовы этой функции с ее кодом.
В вашем случае, вы объявили конструктор Date
следующим образом:
Date(int y, int m, int d); // объявление конструктора
Но не реализовали его. Это значит, что компилятор не знает, как именно следует инициализировать объект Date
. По этой причине, когда линкер пытается найти реализацию конструктора, он не может ее найти, что приводит к указанной ошибке.
Чтобы исправить эту ошибку, вы должны добавить реализацию конструктора. Вот несколько способов, как это можно сделать:
Способ 1: Объявление и реализация в одном месте
Вы можете объявить и реализовать конструктор на одном уровне в коде:
struct Date {
int y, m, d;
Date(int y, int m, int d) : y(y), m(m), d(d) {} // объявление и реализация
// остальные методы...
};
Способ 2: Отдельное объявление и реализация
Если вам нужно разделить объявление и реализацию, вы можете сделать это следующим образом:
struct Date {
int y, m, d;
Date(int y, int m, int d); // объявление конструктора
// остальные методы...
};
// реализация конструктора
Date::Date(int y, int m, int d)
: y(y), m(m), d(d)
{
}
Не забудьте, что помимо конструктора Date
, у вас также может быть проблема с методом add_day(int n)
, который вы объявили, но не реализовали. Если вы собираетесь использовать этот метод, вам также потребуется его реализация.
Пример реализации метода add_day
:
void Date::add_day(int n) {
// Здесь должна быть логика для добавления n дней к дате
// Например, изменяем день и при необходимости корректируем месяц и год
}
Таким образом, инициализируя ваш класс с помощью полноценного определения конструктора и остальных методов, вы устраните данную ошибку линковки.