У меня есть 5 файлов, основной файл и два класса с двумя такими заголовочными файлами:
файл main.cpp:
#include "parent.hpp"
#include <iostream>
int main (){
Parent parentInstance;
parentInstance.function();
return 0;
}
файл parent.hpp:
class Parent {
public:
void function();
};
файл parent.cpp:
#include "child1.hpp"
void Parent::function() {
Child1 Child1Instance;
Child1Instance.speak();
}
файл child1.hpp:
#include "parent.hpp"
#include <iostream>
class Child1 : public Parent {
public:
void speak();
};
файл child1.cpp:
#include "child1.hpp"
void Child1::speak () {
std::cout << "Hi, I'm child1" << '\n';
}
Он компилируется и работает без каких-либо проблем - хотя, возможно, это было сделано с плохой практикой -. Проблема возникает, когда я пытаюсь добавить новый класс с его собственными файлами cpp и hpp с именем Child2, который в основном тот же код, что и Child1, но я не знаю, как правильно организовать заголовки, чтобы этот код работал:
void Parent::function() {
Child1 Child1Instance;
Child2 Child2Instance;
Child1Instance.speak();
Child2Instance.speak();
}
и верни мне:
Hi, I'm child1
Hi, I'm child2
Почему нельзя просто включить child2.hpp так же, как это было с child1.hpp? С какой именно проблемой вы столкнулись?
@ Karsten-Koop, компилятор с ошибками: parent.hpp: 2: 7: error: переопределение «class Parent» parent.hpp: 2: 7: error: предыдущее определение «class Parent»
@Someprogrammerdude - вот почему мне так не нравится эта аналогия "ребенок-родитель". Для меня не имеет никакого смысла говорить, что ребенок является родителем, когда вы наследуете «дочерний» класс от «родительского» класса, это полностью вводит в заблуждение.
Если Parent::function() пытается создать экземпляры нескольких классов, компилятору требуется видимость определения всех этих типов классов. Это достигается включением всех соответствующих заголовков. Кроме того, поскольку у вас будет parent.h, включенный несколькими заголовками, для него необходимо иметь защиту включения.
@ user463035818 и какой-то чувак-программист, спасибо, теперь я понимаю проблему имени. Я просто выбрал эти имена в спешке для этого примера, они не являются именами реального кода.





Некоторые правила:
#pragma once)..cpp включает соответствующий .hpp в качестве своей первой (без комментариев) строки..cpp только то, что вы явно используете в этом .cpp.Это должно решить большинство ваших проблем.
Некоторые пояснения:
a.h и b.h, но b.h уже включает a.h ... Это вызывает некоторые сбивающие с толку ошибки переопределения..cpp соответствовала декларации в .hpp. Ставить его на первой строчке - это просто хорошая практика.#include где-то еще.Очень благодарен за комментарии, все мои знания - самоучка ... теперь проблема решается легко:
main.cpp без изменений.
файл parent.hpp:
#ifndef _PARENT_HPP_
#define _PARENT_HPP_
class Parent {
public:
void function();
};
#endif /* _PARENT_HPP_ */
файл parent.cpp:
#include "parent.hpp"
#include "child1.hpp"
#include "child2.hpp"
void Parent::function() {
Child1 Child1Instance;
Child2 Child2Instance;
Child1Instance.speak();
Child2Instance.speak();
}
файлы child1.hpp и child2.hpp (измените 1 на 2):
#include "parent.hpp"
#include <iostream>
class Child1 : public Parent {
public:
void speak();
};
файл child1.cpp и child2.cpp (измените 1 на 2):
#include "child1.hpp"
void Child1::speak () {
std::cout << "Hi, I'm child1" << '\n';
}
И результат:
Hi, I'm child1
Hi, I'm child2
Оно работает. Однако я хотел бы услышать, есть ли что-нибудь, что можно улучшить, или ошибку, которую можно исправить.
Я не вижу здесь цели наследования. Помните, что наследование - это отношения «есть», например
Child1действительноParent? Возможно, вам следует иметь «родительский» класс отдельный только дляChild1иChild2(тот, который отличается от классаParent, который вы показываете), в которых объявлена виртуальная абстрактная функцияspeak?