С++: Проблема с перегрузкой оператора в классе
Изучаю книгу по С++ и играюсь с перегрузкой операторов.
Следующий код без перегрузки операторов operator FirstMainPart() и operator SecondMainPart() компилируется и работает, но с ней компилятор выдает ошибку:
cpp_book4.cpp: In member function 'MainObject::operator FirstMainPart()': cpp_book4.cpp:23:3: error: return type 'class FirstMainPart' is incomplete { ^ cpp_book4.cpp:24:34: error: invalid use of incomplete type 'class FirstMainPart' return new FirstMainPart(this); ^ cpp_book4.cpp:4:7: note: forward declaration of 'class FirstMainPart' class FirstMainPart; ^~~~~~~~~~~~~
И дальше про второй объект то же самое, хотя объявление данных классов вначале программы есть.
#include <iostream>
class FirstMainPart;
class SecondMainPart;
class MainObject {
public:
MainObject() {}
void get_first()
{
std::cout << "First" << std::endl;
}
void get_second()
{
std::cout << "Second" << std::endl;
}
operator FirstMainPart() { return new FirstMainPart(this); }
operator SecondMainPart() { return new SecondMainPart(this); }
};
class FirstMainPart {
private:
MainObject * obj;
public:
FirstMainPart() {}
FirstMainPart (MainObject * _obj) : obj(_obj) {}
void print_first()
{
obj->get_first();
}
};
class SecondMainPart {
private:
MainObject * obj;
public:
SecondMainPart (MainObject * _obj) : obj(_obj) {}
void print_second()
{
obj->get_second();
}
};
int main()
{
MainObject * o = new MainObject;
std::cout << "done" << std::endl;
return 0;
}
Ответы (1 шт):
Решил вот так:
#include <iostream>
class FirstMainPart;
class SecondMainPart;
class MainObject {
public:
MainObject() {}
void get_first()
{
std::cout << "First" << std::endl;
}
void get_second()
{
std::cout << "Second" << std::endl;
}
operator FirstMainPart();
operator SecondMainPart();
};
class FirstMainPart {
private:
MainObject * obj;
public:
FirstMainPart() {}
FirstMainPart(MainObject * _obj) : obj(_obj) {}
void print_first()
{
obj->get_first();
}
};
class SecondMainPart {
private:
MainObject * obj;
public:
SecondMainPart(MainObject * _obj) : obj(_obj) {}
void print_second()
{
obj->get_second();
}
};
int main()
{
MainObject * o = new MainObject;
std::cout << "done" << std::endl;
return 0;
}
MainObject::operator FirstMainPart()
{
return FirstMainPart(this);
}
MainObject::operator SecondMainPart()
{
return SecondMainPart(this);
}
- Убрал
newиз операторов - Перенёс определения операторов в самый низ, в классе оставил только объявления. (Недаром так советуют делать во всех учебниках).
Теперь о причинах ошибок:
Написав вверху
class FirstMainPart;
class SecondMainPart;
Вы "рассказали" компилятору, что такие классы есть. И всё. "Ни слова" об их составе и поведении, в том числе и об аргументах конструктора.
Далее Вы вызываете конструкторы этих классов в операторах класса MainObject. И передаёте конструкторам аргументы. Но на этом моменте компилятор ещё "не дочитал" до полноценного описания конструкторов, а потому понятия не имеет, какие аргументы эти конструкторы принимают, не удалены ли они вообще и т.д. Потому и ругается.
Первое решение, пришедшее в голову, – поместить определения классов FirstMainPart и SecondMainPart выше определения класса MainObject, чтобы из операторов было "видно" информацию о конструкторах. Но тут возникает проблема. В этих двух классах используются методы класса MainObject, которых, опять же, "не видно", потому что они описаны ниже.
А значит, остаётся то, что я и сделал – поместить определения методов-операторов в самый низ или, по крайней мере, ниже определения классов FirstMainPart и SecondMainPart. В таком случае, когда компилятор дойдёт до этих операторов, он уже успеет "прочитать" выше о конструкторах нужных классов и их аргументах. При этом сам класс MainObject, как и его методы get_first() и get_second() будут объявлены над кассами FirstMainPart и SecondMainPart, что позволит беспрепятственно их вызвать.
P.S. Совет на будущее – разделяйте объявления и определения членов класса. Книжки по С++ плохого, как правило, не советуют.