I have been banging my head against the wall trying to debug this code. It is my first time using CMake and splitting code between different header files so bare with me.
When running make, I have been getting this error:
[ 33%] Building CXX object CMakeFiles/ConceptWeatherTest.dir/concept_weather_test.cpp.o
[ 66%] Building CXX object CMakeFiles/ConceptWeatherTest.dir/displays_weather.cpp.o
[100%] Linking CXX executable ConceptWeatherTest
/usr/bin/ld: CMakeFiles/ConceptWeatherTest.dir/concept_weather_test.cpp.o: in function `main':
concept_weather_test.cpp:(.text+0x40): undefined reference to `concept_weather::CurrentConditionsDisplay::CurrentConditionsDisplay(concept_weather::WeatherData*)'
/usr/bin/ld: concept_weather_test.cpp:(.text+0x5c): undefined reference to `concept_weather::StatisticsDisplay::StatisticsDisplay(concept_weather::WeatherData*)'
/usr/bin/ld: concept_weather_test.cpp:(.text+0x78): undefined reference to `concept_weather::ForecastDisplay::ForecastDisplay(concept_weather::WeatherData*)'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/ConceptWeatherTest.dir/build.make:99: ConceptWeatherTest] Error 1
make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/ConceptWeatherTest.dir/all] Error 2
make: *** [Makefile:84: all] Error 2
What I have is three abstract classes and four concrete classes that inherit things from those abstract classes. Here's the three abstract classes:
#ifndef CONCEPT_WEATHER_HPP
#define CONCEPT_WEATHER_HPP
#include <algorithm>
#include <vector>
namespace concept_weather {
class Observer {
public:
virtual void update() {}
};
class Subject {
protected:
std::vector<Observer *> observers{};
public:
void register_observer(Observer *o) { observers.push_back(o); }
void remove_observer(Observer *o) {
observers.erase(std::find(observers.begin(), observers.end(), o));
}
void notify_observers() {
for (auto o : observers) {
o->update();
}
}
};
class DisplayElement {
public:
virtual void display() {}
};
} // namespace concept_weather
#endif
And here are two of the concrete ones (the remaining two are similar to CurrentConditionsDisplay):
#ifndef DATA_WEATHER_HPP
#define DATA_WEATHER_HPP
#include "concept_weather.hpp"
namespace concept_weather {
class WeatherData : virtual public Subject {
private:
float temperature{};
float humidity{};
float pressure{};
public:
WeatherData() {}
void set_measurements(float temp, float hum, float press) {
temperature = temp;
humidity = hum;
pressure = press;
notify_observers();
}
float get_temperature() { return temperature; }
float get_humidity() { return humidity; }
float get_pressure() { return pressure; }
};
} // namespace concept_weather
#endif
#ifndef DISPLAYS_WEATHER_HPP
#define DISPLAYS_WEATHER_HPP
#include "data_weather.hpp"
#include <iostream>
namespace concept_weather {
class CurrentConditionsDisplay : virtual public Observer,
virtual public DisplayElement {
private:
float temperature;
float humidity;
WeatherData *station;
public:
CurrentConditionsDisplay(WeatherData *o);
void update();
void display();
};
// more code goes here
} // namespace concept_weather
#endif
This was a bigger header so I split the code up into a .hpp and a .cpp.
#include "displays_weather.hpp"
using namespace std;
using namespace concept_weather;
class CurrentConditionsDisplay : virtual public DisplayElement,
virtual public Observer {
private:
float temperature{};
float humidity{};
WeatherData *station = nullptr;
public:
CurrentConditionsDisplay(WeatherData *o) : station(o) {
station->register_observer(this);
}
void update() {
temperature = station->get_temperature();
humidity = station->get_humidity();
display();
}
void display() {
cout << "Current conditions: " << temperature << "F degrees and "
<< humidity << "% humidity" << endl;
}
};
// more code goes here
Here is what my test file with my main function has:
#include "displays_weather.hpp"
using namespace concept_weather;
using namespace std;
int main() {
auto *weather_data = new WeatherData;
new CurrentConditionsDisplay(weather_data);
new StatisticsDisplay(weather_data);
new ForecastDisplay(weather_data);
weather_data->set_measurements(80, 65, 30.4);
weather_data->set_measurements(82, 70, 29.2);
weather_data->set_measurements(78, 90, 29.2);
}
Here is also what my CMakeLists.txt looks like:
cmake_minimum_required(VERSION 3.16)
# set the project name
project(ConceptWeatherTest)
# find sources here
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -iquote ${PROJECT_SOURCE_DIR}")
# set sources here
set(SOURCES concept_weather_test.cpp concept_weather.hpp data_weather.hpp displays_weather.cpp displays_weather.hpp)
# add the executable
add_executable(ConceptWeatherTest ${SOURCES})
Does anyone have any ideas about what I missed?