I have this problem:
Problem:
I am trying to create a library (ard33WiFi) that manages and handles
a couple of other libraries (WiFiServer library for example)
I need to create the server object that I then use in functions in my Library (ard33WiFi):
WiFiServer myServer(iPort);
The problem is that when I call myServer in the members of the class I get:
'myServer' was not declared in this scope
Where/how do I declare myServer so that is becomes available to the entire class (ard33WiFi)? I have taken out any decleration because whatever I was trying was wrong. I have pasted a skeleton code below.
// HEADER FILE (.h)
// ----------------------------------------------------------------------------------------------
#ifndef Ard33WiFi_h
#define Ard33WiFi_h
#include <WiFiNINA.h>
#include <WiFiUdp.h>
class ard33WiFi{
public:
ard33WiFi(int iPort)
void someFunction();
void serverBegin();
private:
int _iPort;
};
#endif
// ----------------------------------------------------------------------------------------------
// C++ FILE (.cpp)
// -----------------------------------------------------------------------------------------------
#include <Ard33Wifi.h>
ard33WiFi::ard33WiFi(int iPort){
_iPort = iPort;
}
void ard33WiFi::someFunction(){
// code here required to prepare the server for initializing
// but ultimately not relevant to the question
}
void ard33WiFi::serverBegin(){
myServer.begin();
Serial.println("Server Online");
}
I run into the same problem with the UDP library as I need to call the UDP object in various functions to do UDP things.
Any help would be greatly appreciated.
I suppose you are using this:
https://www.arduino.cc/en/Reference/WiFiServer
I can see that you are not declaring the myServer in your class; that I guess is the error in your code. If I am not wrong, it should be something like this:
#ifndef Ard33WiFi_h
#define Ard33WiFi_h
#include <WiFiNINA.h>
#include <WiFiUdp.h>
#include <WiFi.h> // Not sure if you have to append this include
class ard33WiFi{
public:
ard33WiFi(int iPort)
void someFunction();
void serverBegin();
private:
int _iPort;
WiFiServer myServer;
};
#endif
The implementation, you would need to initialise the instance:
#include <Ard33Wifi.h>
ard33WiFi::ard33WiFi(int iPort):myServer(iPort), _iPort(iPort) {
}
void ard33WiFi::someFunction(){
// code here required to prepare the server for initializing
// but ultimately not relevant to the question
}
void ard33WiFi::serverBegin(){
myServer.begin();
Serial.println("Server Online");
}
Related
I want to use a class: class2, within a class: class1. From what I read, to prevent a circular dependency, one must forward declare class2 in class1.h and have it be a pointer. After calling a function from class2 in my class1.cpp file. I'm unable to call the variables within class2 without getting "Unable to read memory" or a nullptr.
Here's my code, thank you for the help:
//main.cpp
#include "Login.h"
#include <iostream>
using namespace std;
int main() {
Login login;
login.StartMenu();
cout << "ENDING" << endl;
system("pause");
return 0;
}
//Login.h (Class1)
#pragma once
#include <iostream>
using namespace std;
class GameManager;
class Login {
public:
void StartMenu();
private:
GameManager* manager;
};
//Login.cpp
#include "Login.h"
#include "GameManager.h"
void Login::StartMenu() {
manager->GameStart();
}
//GameManager.h (Class2)
#pragma once
class GameManager {
public:
void GameStart();
private:
int level = 1;
};
//GameManager.cpp
#include "Login.h"
#include "GameManager.h"
void GameManager::GameStart() {
cout << level;
}
Generally, it is a good idea to keep dependencies between headers to a minimum, and using pointers for classes that are only forward-declared is an established way to do that. This is good practice even if there are no circular dependencies because it can greatly reduce recompilation times in large projects.
Regarding your specific question: Essentially, the Login class, and especially the Login::StartMenu function, needs to know which GameManager instance to use. A pointer to that instance will be stored in manager. Ideally you can tell that at construction time of a Login instance via a GameManager * constructor argument:
#ifndef LOGIN_H
#define LOGIN_H
class GameManager;
/// This class handles the login procedure for a specific
/// game manager which must be provided to the constructor.
/// It cannot be copied (so it cannot be
/// in arrays) or default-constructed.
class Login {
public:
/// The constructor does nothing except initializing manager.
/// #param gmPtr is a pointer to the game manager
/// this instance is using.
void Login(GameManager *gmPtr)
: manager(gmPtr) { /* empty */ }
void StartMenu();
private:
GameManager* manager;
};
#endif // LOGIN_H
For completeness, here is how you would use it:
#include "Login.h"
#include "GameManager.h"
#include <iostream>
using namespace std;
int main() {
GameManager gm;
Login login(&gm); // <-- provide game manager to login
login.StartMenu();
cout << "ENDING" << endl;
system("pause");
return 0;
}
If that is not possible because the GameManager instance does not exist yet or is otherwise unknown during construction of a Login instance (for example, if you have an array of Login instances, whose elements must be default-constructed) you can provide the argument to the Login::StartMenu method. But the constructor argument is much preferred because you can then be sure that the class is functional in the rest of the code — this kind of "invariants" are the main reason why constructors exist.
It is certainly possible that you don't need to hold a pointer at all, if all functions get that pointer argument. Whether the Login class has a one-to-one relationship with a GameManager (in which case it simply holds a pointer to it) or not (in which case every function is told each time) is a design decision.
I am attempting to create this header file:
#define MqttConfig_h
#include "Arduino.h"
#include <PubSubClient.h> // MQTT client
#include <ESP8266WiFi.h> // ESP8266 Core WiFi Library
#include <Config.h>
class MqttConfig
{
public:
MqttConfig();
void initMQTT();
private:
String _mqttServer;
String _mqttPrefix;
WiFiClient _wifi;
PubSubClient _mqttClient(_wifi); ****** ERROR HERE *******
};
#endif
I've tried various ways to make it work:
// This seemed logical to me
PubSubClient _mqttClient(WiFiClient{});
// This was an attempt to read the field and pass it back
WiFiClient GetWiFiClient();
PubSubClient _mqttClient(GetWiFiClient());
// This compiles, but does something I don't understand
WiFiClient GetWiFiClient();
PubSubClient _mqttClient(WiFiClient);
What is the right way to "chain up fields" in the header file? I'll note that I don't care about a reference to the _wifi object, I'm making it because the constructor of the PubSubClient object wants it..
In general, you initialize fields in your constructor:
class MqttConfig
{
public:
MqttConfig();
private:
PubSubClient _mqttClient;
};
// ...
MqttConfig::MqttConfig()
: _mqttClient(WiFiClient{})
{
}
As for your last attempt:
// This compiles, but does something I don't understand
WiFiClient GetWiFiClient();
PubSubClient _mqttClient(WiFiClient);
These are method declarations.
I want to make a class in cpp for arduino uno that writes on a display. I'm using the LiquidCrystal_I2C library but I can't use it in my class. I know how to do it without a class, but right now I want to build a class and I cant get it to work.
My .h file:
// WriteDisplay.h
#ifndef _WRITEDISPLAY_h
#define _WRITEDISPLAY_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
#include <Wire/Wire.h>
#include <LiquidCrystal_I2C2004V1/LiquidCrystal_I2C.h>
class WriteDisplayClass
{
public:
WriteDisplayClass();
void write(String text);
private:
LiquidCrystal_I2C lcd(0x27,20,4);
};
extern WriteDisplayClass WriteDisplay;
#endif
My .cpp:
#include "WriteDisplay.h"
WriteDisplayClass::WriteDisplayClass()
{
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
}
WriteDisplayClass::write(String text)
{
lcd.clear();
lcd.print(text);
}
WriteDisplayClass WriteDisplay;
My .ino:
#include "WriteDisplay.h"
WriteDisplayClass wdc;
void setup()
{
wdc.write("Hello World");
}
void loop()
{
}
I'm using AtmelStudio with Visual Micro. I'm getting it to work when I'm only using my .ino-file, but I can't do the same thing in cpp. I'm getting errors that LiquidCrystal_I2C.h can't be found and stuff like that. How should I do to get it to work the way I want it to? Or is it even possible?
Thanks for answer.
Sorry I misread the question the first time.
To use libraries in the .cpp file of an Arduino sketch you must also include them in the master .ino file. They are only compiled if found in the .ino
You can add the includes manually or use the "Project>Add/Import Sketch Library" menu item which will add them to the .ino for you.
Based on this post here the problem with your code is related the class being instantiated as global. The problem comes that the compiler doesn't guarantee the order of global variables processing, so in order to guarantee that the object concerning the display is executed lastly after all the library ones, you have to instantiate it in the setup() function!
The solution to your .ino code is to set a global pointer and then you assign the object inside the setup() function, like so:
#include "WriteDisplay.h"
WriteDisplayClass *wdc;
void setup()
{
wdc = new WriteDisplayClass();
wdc->write("Hello World");
}
void loop()
{
}
I'm trying to create a game in C++.
It has a "Session" class that kind of manages everything. It contains things like a GraphicsManager, a SoundManager, and the current world. It also contains a static pointer to an instance of itself. This way, I want the world to be available for the GraphicsManager so it can be rendered, for example.
Here is a simplified version of my code:
main.ccp
#pragma once
#include "Session.h"
int main() {
Session::getSession()->run(); //Starts a new session and runs it
return 0;
}
Session.h
#pragma once
#include "GraphicsManager.h"
#include "World.h"
class Session; //Forward declaration so it can have a pointer to itself
class Session {
private:
Session();
static Session* s;
World* w; //Pointer because no world is loaded at the beginning of the program
GraphicsManager gm; //Required right away
public:
~Session();
void run(); //Actually launches the game after preparation; not further declared in this example
World* getWorld(); //Returns the pointer to the current world
static Session* getSession();
}
Session.cpp
#include "Session.h"
Session::Session(): gm(GraphicsManager()) {}
Session* Session::getSession() { //Return an instance of Session. If no instance exist yet, create one.
if(s == NULL) s = new Session();
return s;
}
World* Session::getWorld() {return w;} //Returns a pointer to the current world
GraphicsManager.h
#pragma once;
class GraphicsManager {
private:
void render();
public:
void run(); //Calls the render method repeatedly; no further declaration in this example
}
GraphicsManager.cpp
#include "GraphicsManager.h"
void GraphicsManger::render() {
World* w = Session::getSession()->getWorld(); //Get pointer to current world so it can be rendered
}
The render method is where I'm stuck. If I put #include "Session.h" into the GraphicsManager.h file, it gives me an error because apparently two header files cannot include each other. If I put a forward declaration at the beginning of GraphicsManager.h or GraphicsManager.cpp, Visual Studio tells me that incomplete types are not permitted.
This has been giving me a headache for weeks. I've made games in Java before and there this pattern was accepted. So how can I do this? If this structure is not possible in C++, do you have other suggestions for it?
In GraphicsManager.cpp, the compiler needs to know about the Session, so you have to #include "Session.h" which by the way includes GraphicsManager as well as World.
A forward definition will not be sufficient, as the compiler would not be able to check types of getSession()->getWorld() expression.
Apparently your GraphicsManager.h doesn't rely itself on the other definitions, so there should'nt be an issue here.
Try to include Session.h to GraphicsManager.cpp:
#include "Session.h"
void GraphicsManger::render() {
World* w = Session::getSession()->getWorld(); //Get pointer to current world so it can be rendered
}
This way Session class defenition will be visible for compiler in GraphicsManager.cpp, so it will not generate incomplite type error. On the other hand, Session.h is not included to GraphicsManager header, so there will no problem that both headers include each other.
As a follow up to an older question of mine, I wish to implement a client-server mockup simulation, where the client initiates a sequence of actions that involve calling methods on the server, which, in turn, can call methods on the client (let's ignore the issue that the stack may blow up).
More specifically, since I want to split the implementation from the definition, I will have server.h and server.cpp for the Server class and client.h and client.cpp for the Client class. Since Server holds a reference to Client and calls methods from it, it needs to #include "client.h". Also, Client holds a reference to Server and calls methods from it, it needs to #include "server.h". At this point, even if I use header guards in both server.h and client.h, it still messes up (yeah, it's expected) so I decided to forward-declare the Server class in client.h and the Client class in server.h. Unfortunately, this is not enough to solve the issue, because I'm also calling methods from the two classes, so I managed to make it compile & run (properly, as far as I can tell), by including server.h in client.cpp and client.h in server.cpp.
Does the above "hack" sound reasonable? Should I expect some unforeseen consequences? Is there any "smarter" way to do this without having to implement a proxy class?
Here's a rudimentary sample of how the implementation will look like:
file client.h:
#ifndef CLIENT_H
#define CLIENT_H
#include <iostream>
#include <memory>
class Server;
class Client
{
private:
std::shared_ptr<const Server> server;
public:
Client () {}
void setServer (const std::shared_ptr<const Server> &server);
void doStuff () const;
void doOtherStuff () const;
};
#endif
file client.cpp:
#include "client.h"
#include "server.h"
void Client::setServer (const std::shared_ptr<const Server> &server)
{
this->server = server;
}
void Client::doStuff () const
{
this->server->doStuff();
}
void Client::doOtherStuff () const
{
std::cout << "All done!" << std::endl;
}
file server.h:
#ifndef SERVER_H
#define SERVER_H
#include <iostream>
#include <memory>
class Client;
class Server
{
private:
std::weak_ptr<const Client> client;
public:
Server () {}
void setClient (const std::weak_ptr<const Client> &client);
void doStuff () const;
};
#endif
file sever.cpp:
#include "server.h"
#include "client.h"
void Server::setClient (const std::weak_ptr<const Client> &client)
{
this->client = client;
}
void Server::doStuff () const
{
this->client.lock()->doOtherStuff();
}
file main.cpp:
#include <iostream>
#include <memory>
#include "client.h"
#include "server.h"
int main ()
{
std::shared_ptr<Client> client(new Client);
std::shared_ptr<Server> server(new Server);
client->setServer(server);
server->setClient(client);
client->doStuff();
return 0;
}
That looks good to me. Forward declaring server in the client.h and forward declaring client in the server.h is the right thing to do.
It is perfectly fine to then include both header files in the .c or .cpp file - all you need to avoid is including the header files in a circle.
The "Hack" is none, it's perfectly common practice to separate declaration and implementation of the two classes as you did. And it's perfectly normal that the *.cpp include both Headers.
Sidenote: First consider different signatures for your setServer and setClient methods: In both methods, you copy the argument. Both copies are nontrivial, since the use_counts and/or weak_count have to be updated. If the argument indeed is an existing argument, that is ok, but if it is a temporary, the copy will increase the count and destruction of the temporary will decrease it again, each time an internal pointer has to be dereferenced. In contrast, moving a shared_ptr or weak_ptr does not affect the use counts but resets the temporary. Destruction of that reset temporary again does not affect the use count (it effectively is a null pointer).
Secondly, always prefer make_shared over simple new, because it saves you one allocation. So use this implementation instead:
void Client::setServer (std::shared_ptr<const Server> server)
{
this->server = std::move(server);
}
int main ()
{
auto client = std::make_shared<Client>(); //prefer make_shared
auto server = std::make_shared<Server>();
/* 1 */
client->setServer(server); //by copy, if you need to continue to use server
/* 2 */
server->setClient(std::move(client)); //by moving
}
Call 1 will be as expensive at it was, you make one copy pf the shared_ptr, only this time you make it while passing the argument, not inside the method. Call 2 will be cheaper, because the shared_ptr is moved around and never copied.
My following statement is false (see comments) and applies only to unique_ptr, not to shared_ptr:
But: Since you use a std::shared_ptr<const Server> in Client, you
will have to define Client's destructor inside client.cpp. The
reason is that if you don't, the compiler will generate it for you,
calling the shared_ptr's and thus Server's destructor which has
not been declared inside client.h. At reasonably high warning levels
you compiler should complain about calling delete on a an undefined
class' pointer.
Does the above "hack" sound reasonable? Should I expect some
unforeseen consequences? Is there any "smarter" way to do this without
having to implement a proxy class?
Forward declaration and use include directive to is the normal and right way to break circular include.