-
I can generally follow conventional C code, but get pretty lost with C++, hopefully my terminology is close enough to convey my question
Assume I have a project with multiple files and multiple (not sure if their called classes or methods) in these various files and I want to access one of the variables that is inside a class while I'm in another class or even main()?
For example....
I can access leds.bit.FEED while in UserInterface::calculatedLEDs(), see the printf below, however if I try to access this from say main() again just using a printf, the compiler throws an error because "leds" is undefined. I'm not sure what the correct syntax is to access from main(),I think I either need a bunch of . this.that etc or possible this-> but I'm really not sure?
LED_REG UserInterface::calculateLEDs()
{
// get the LEDs for this feed
LED_REG leds = feedTable->current()->leds;
if( this->core->isPowerOn() )
{
leds.bit.POWER = 1;
leds.bit.REVERSE = this->reverse;
leds.bit.FORWARD = ! this->reverse;
if (leds.bit.FEED == 1)
printf("feed\n");
}
else
{
// power is off
leds.all = 0;
}
return leds;
}
-
"leds" is a local variable to this function, it only exists when function is running. What you need to know what "feedTable" is. And this is not shown here. Once feedTable is accessible, you can do the same exact thing to get to "leds".
-
feedTable is likely a member of the User interface class... see if it is defined in a file named UserInterface.h.
If so, you'll have to find a reference to the UserInterface object and use that in main with code like "ui->feedTable" where "ui" us the reference. Let us know what you find out.
-
"leds" is a local variable to this function, it only exists when function is running. What you need to know what "feedTable" is. And this is not shown here. Once feedTable is accessible, you can do the same exact thing to get to "leds".
In main.cpp before main() we have:
FeedTableFactory feedTableFactory;
UserInterface userInterface(&controlPanel, &core, &feedTableFactory);
In UserInterface.cpp we have the following
UserInterface :: UserInterface(ControlPanel *controlPanel, Core *core, FeedTableFactory *feedTableFactory)
{
this->controlPanel = controlPanel;
this->core = core;
this->feedTableFactory = feedTableFactory;
this->metric = false; // start out with imperial
this->thread = false; // start out with feeds
this->reverse = false; // start out going forward
this->feedTable = NULL;
this->keys.all = 0xff;
// initialize the core so we start up correctly
core->setReverse(this->reverse);
core->setFeed(loadFeedTable());
setMessage(&STARTUP_MESSAGE_1);
}
const FEED_THREAD *UserInterface::loadFeedTable()
{
this->feedTable = this->feedTableFactory->getFeedTable(this->metric, this->thread);
return this->feedTable->current();
}
-
Impossible to answer, unless you provide the classes definitions, and their inheritance(s) !
-
Impossible to answer, unless you provide the classes definitions, and their inheritance(s) !
Do these help?
class UserInterface
{
private:
ControlPanel *controlPanel;
Core *core;
FeedTableFactory *feedTableFactory;
bool metric;
bool thread;
bool reverse;
FeedTable *feedTable;
KEY_REG keys;
const MESSAGE *message;
Uint16 messageTime;
const FEED_THREAD *loadFeedTable();
LED_REG calculateLEDs();
void setMessage(const MESSAGE *message);
void overrideMessage( void );
void clearMessage( void );
public:
UserInterface(ControlPanel *controlPanel, Core *core, FeedTableFactory *feedTableFactory);
void loop( void );
void panicStepBacklog( void );
};
-----------------------------------------------------------------------------------------------------
class ControlPanel
{
private:
// Common SPI Bus
SPIBus *spiBus;
// Current RPM value; 4 decimal digits
Uint16 rpm;
// Current displayed setting value, 4 digits
const Uint16 *value;
// Current LED states
LED_REG leds;
// current key states
KEY_REG keys;
// number of times current key state has been seen
KEY_REG stableKeys;
Uint16 stableCount;
// current override message, or NULL if none
const Uint16 *message;
// brightness, levels 1-8, 0=off
Uint16 brightness;
// Derived state, calculated internally
Uint16 sevenSegmentData[8];
// dummy register, for SPI
Uint16 dummy;
void decomposeRPM(void);
void decomposeValue(void);
KEY_REG readKeys(void);
Uint16 lcd_char(Uint16 x);
void sendByte(Uint16 data);
Uint16 receiveByte(void);
void sendData(void);
Uint16 reverse_byte(Uint16 x);
void initSpi();
void configureSpiBus(void);
bool isValidKeyState(KEY_REG);
bool isStable(KEY_REG);
public:
ControlPanel(SPIBus *spiBus);
// initialize the hardware for operation
void initHardware(void);
// poll the keys and return a mask
KEY_REG getKeys(void);
// set the RPM value to display
void setRPM(Uint16 rpm);
// set the value to display
void setValue(const Uint16 *value);
// set the LED states
void setLEDs(LED_REG leds);
// set a message that overrides the display, 8 characters required
void setMessage(const Uint16 *message);
// set a brightness value, 0 (off) to 8 (max)
void setBrightness(Uint16 brightness);
// refresh the hardware display
void refresh(void);
};
-
Not really, as many information is missing.
But it seems you are attempting to access a private member from outside.
-
Based on:
UserInterface userInterface(&controlPanel, &core, &feedTableFactory);
I would try in main() something like:
LED_REG leds = userInterface.feedTable->current()->leds;
...
It is quite possible, however, that feedTable has not been made visible outside of the UserInterface class.
An alternative is to add a new method in the UserInterface class which returns feedTable so that free-standing functions like main can access it. The member function loadFeedTable() might do this for you if the getFeedTable() call always returns the same feedTable (as opposed to allocating a new one every time it is called.)
Update: I see that both feedTable and loadFeedTable() are marked private, so you won't be able to access them. I would add a new public method if you really need to access the feedTable from main().
-
feedTable is a private member of the UserInterface class. So, you can't readily access it. You need to add a public method to either get feedTable or just leds part.
This code is also a typical C++ pile of garbage.
-
In main.cpp before main() we have:
FeedTableFactory feedTableFactory;
UserInterface userInterface(&controlPanel, &core, &feedTableFactory);
In UserInterface.cpp we have the following
UserInterface :: UserInterface(ControlPanel *controlPanel, Core *core, FeedTableFactory *feedTableFactory)
{
this->controlPanel = controlPanel;
this->core = core;
this->feedTableFactory = feedTableFactory;
this->metric = false; // start out with imperial
this->thread = false; // start out with feeds
this->reverse = false; // start out going forward
this->feedTable = NULL;
this->keys.all = 0xff;
// initialize the core so we start up correctly
core->setReverse(this->reverse);
core->setFeed(loadFeedTable());
setMessage(&STARTUP_MESSAGE_1);
}
const FEED_THREAD *UserInterface::loadFeedTable()
{
this->feedTable = this->feedTableFactory->getFeedTable(this->metric, this->thread);
return this->feedTable->current();
}
The address of feedTableFactory is passed into the constructor of the UserInterface class when 'userInterface' instance is created. This address is stored locally within this class so it's methods can access feedTableFactory indirectly. You should be able to access the same data and methods from main() directly using the feedTableFactory class instance e.g. feedTableFactory.current()->leds
Is this the Clough42 electronic feedscrew project?
-
In main.cpp before main() we have:
FeedTableFactory feedTableFactory;
UserInterface userInterface(&controlPanel, &core, &feedTableFactory);
In UserInterface.cpp we have the following
UserInterface :: UserInterface(ControlPanel *controlPanel, Core *core, FeedTableFactory *feedTableFactory)
{
this->controlPanel = controlPanel;
this->core = core;
this->feedTableFactory = feedTableFactory;
this->metric = false; // start out with imperial
this->thread = false; // start out with feeds
this->reverse = false; // start out going forward
this->feedTable = NULL;
this->keys.all = 0xff;
// initialize the core so we start up correctly
core->setReverse(this->reverse);
core->setFeed(loadFeedTable());
setMessage(&STARTUP_MESSAGE_1);
}
const FEED_THREAD *UserInterface::loadFeedTable()
{
this->feedTable = this->feedTableFactory->getFeedTable(this->metric, this->thread);
return this->feedTable->current();
}
The address of feedTableFactory is passed into the constructor of the UserInterface class when 'userInterface' instance is created. This address is stored locally within this class so it's methods can access feedTableFactory indirectly. You should be able to access the same data and methods from main() directly using the feedTableFactory class instance e.g. feedTableFactory.current()->leds
Is this the Clough42 electronic feedscrew project?
looks like ti, https://github.com/clough42/electronic-leadscrew
-
In main.cpp before main() we have:
FeedTableFactory feedTableFactory;
UserInterface userInterface(&controlPanel, &core, &feedTableFactory);
In UserInterface.cpp we have the following
UserInterface :: UserInterface(ControlPanel *controlPanel, Core *core, FeedTableFactory *feedTableFactory)
{
this->controlPanel = controlPanel;
this->core = core;
this->feedTableFactory = feedTableFactory;
this->metric = false; // start out with imperial
this->thread = false; // start out with feeds
this->reverse = false; // start out going forward
this->feedTable = NULL;
this->keys.all = 0xff;
// initialize the core so we start up correctly
core->setReverse(this->reverse);
core->setFeed(loadFeedTable());
setMessage(&STARTUP_MESSAGE_1);
}
const FEED_THREAD *UserInterface::loadFeedTable()
{
this->feedTable = this->feedTableFactory->getFeedTable(this->metric, this->thread);
return this->feedTable->current();
}
The address of feedTableFactory is passed into the constructor of the UserInterface class when 'userInterface' instance is created. This address is stored locally within this class so it's methods can access feedTableFactory indirectly. You should be able to access the same data and methods from main() directly using the feedTableFactory class instance e.g. feedTableFactory.current()->leds
Is this the Clough42 electronic feedscrew project?
Yes this is the C42 project
Can you please explain the precise syntax for "feedTableFactory.current()->leds"
I tried LED_REG leds = feedTableFactory.current()->leds; // compiler error is no member current
also tried LED_REG leds = feedTableFactory->current()->leds; // compiler error expression must have pointer type
I did notice that in the public section of the ControlPanel class that this function exists void setLEDs(LED_REG leds) and also KEY_REG getKeys(void); however I need getLEDs
-
I did notice that in the public section of the ControlPanel class that this function exists void setLEDs(LED_REG leds) and also KEY_REG getKeys(void); however I need getLEDs
To add a getLEDs() method you can modify ControlPanel.h as indicated here:
https://gitlab.com/pc88mxer/electronic-leadscrew/-/commit/2fc90ac54af3309fb0e042deee05f51e158d247f?w=1
Complete file:
https://gitlab.com/pc88mxer/electronic-leadscrew/-/blob/2fc90ac54af3309fb0e042deee05f51e158d247f/els-f280049c/ControlPanel.h
-
I did notice that in the public section of the ControlPanel class that this function exists void setLEDs(LED_REG leds) and also KEY_REG getKeys(void); however I need getLEDs
To add a getLEDs() method you can modify ControlPanel.h as indicated here:
https://gitlab.com/pc88mxer/electronic-leadscrew/-/commit/2fc90ac54af3309fb0e042deee05f51e158d247f?w=1
Complete file:
https://gitlab.com/pc88mxer/electronic-leadscrew/-/blob/2fc90ac54af3309fb0e042deee05f51e158d247f/els-f280049c/ControlPanel.h
ledtester thank you
I added your code to ControlPanel.h and it compiles.
I'm having trouble with syntax in main.cpp
I tried LED_REG leds = controlPanel->getLEDs(); // error expression must have pointer type
-
Try:
LED_REG leds = controlPanel.getLEDs();
controlPanel is probably not a pointer -- hence the use of "."
-
Try:
LED_REG leds = controlPanel.getLEDs();
controlPanel is probably not a pointer -- hence the use of "."
It's working. Thanks so much!
:) :)
-
For example....
I can access leds.bit.FEED while in UserInterface::calculatedLEDs(), see the printf below, however if I try to access this from say main() again just using a printf, the compiler throws an error because "leds" is undefined. I'm not sure what the correct syntax is to access from main(),I think I either need a bunch of . this.that etc or possible this-> but I'm really not sure?
LED_REG UserInterface::calculateLEDs()
{
// get the LEDs for this feed
LED_REG leds = feedTable->current()->leds;
if( this->core->isPowerOn() )
{
leds.bit.POWER = 1;
in your example leds is a local variable of type LED_REG which is declared and assigned at the beginning of the class method. Local variable is accessible only in the scope where it is declared (in your example within method function code).
-
For example....
I can access leds.bit.FEED while in UserInterface::calculatedLEDs(), see the printf below, however if I try to access this from say main() again just using a printf, the compiler throws an error because "leds" is undefined. I'm not sure what the correct syntax is to access from main(),I think I either need a bunch of . this.that etc or possible this-> but I'm really not sure?
LED_REG UserInterface::calculateLEDs()
{
// get the LEDs for this feed
LED_REG leds = feedTable->current()->leds;
if( this->core->isPowerOn() )
{
leds.bit.POWER = 1;
in your example leds is a local variable of type LED_REG which is declared and assigned at the beginning of the class method. Local variable is accessible only in the scope where it is declared (in your example within method function code).
I think I'm starting to grasp this somewhat.....
1) Because leds is in the private section of the ControlPanel class, leds is just that private an inaccessible, UNLESS their is a public function that provides access, is that correct?
2) ledtester helped me out by providing a public function..... LED_REG getLEDs(); inline LED_REG ControlPanel :: getLEDs() { return leds;} to do just that. Thanks ledtester!
3) When I call this function in main.cpp like this if(controlPanel.getLEDs().bit.FEED == 1) it compiles and works
3a) I think this is because of this deceleration near the beginning of main.cpp ControlPanel controlPanel(&spiBus); makes the controlPanel object visible in main.cpp? Is this correct?
Now I'm lost again........
4) I tried doing the exact same thing if(controlPanel.getLEDs().bit.FEED == 1) again but this time in a new C function that I created within the ControlPanel.cpp file and this causes a compile error "controlPanel is undefined". So I tried using the same deceleration used in main.cpp but this time in ControlPanel.cpp however that creates a linker error "controlPanel redefined" so it's not clear how I access getLEDs() from within my new function that resides in ControlPanel.cpp?
5) What if....... I simply moved leds to the public section of the ControlPanel class?
Any suggestions?
-
Now I'm lost again........
4) I tried doing the exact same thing if(controlPanel.getLEDs().bit.FEED == 1) again but this time in a new C function that I created within the ControlPanel.cpp file and this causes a compile error "controlPanel is undefined". So I tried using the same deceleration used in main.cpp but this time in ControlPanel.cpp however that creates a linker error "controlPanel redefined" so it's not clear how I access getLEDs() from within my new function that resides in ControlPanel.cpp?
5) What if....... I simply moved leds to the public section of the ControlPanel class?
Any suggestions?
Where in the ControlPanel.cpp file are you placing this new function? Show us what you tried to do.
Within a method of the ControlPanel class you can simply access the variable as "leds". That's how the getLEDs method works:
inline LED_REG ControlPanel :: getLEDs()
{
return leds;
}
-
Now I'm lost again........
4) I tried doing the exact same thing if(controlPanel.getLEDs().bit.FEED == 1) again but this time in a new C function that I created within the ControlPanel.cpp file and this causes a compile error "controlPanel is undefined". So I tried using the same deceleration used in main.cpp but this time in ControlPanel.cpp however that creates a linker error "controlPanel redefined" so it's not clear how I access getLEDs() from within my new function that resides in ControlPanel.cpp?
5) What if....... I simply moved leds to the public section of the ControlPanel class?
Any suggestions?
inline LED_REG ControlPanel :: getLEDs()
{
return leds;
}
Where in the ControlPanel.cpp file are you placing this new function? Show us what you tried to do.
Within a method of the ControlPanel class you can simply access the variable as "leds". That's how the getLEDs method works:
I created a new conventional C function void newFunction(void) at the bottom of ControlPanel.cpp and placed if(controlPanel.getLEDs().bit.FEED == 1) within that function.
I'm now wondering if I should try to make my newFunction, C++ instead, put in inside
void( ControlPanel :: newFunction(void) ????
I tried it and it compiles, looks like I just wrote my first C++ member function testing..... I shall return.
-
Add your new function to main.cpp instead of ControlPanel.cpp.
Yes see, main.cpp defines the variable controlPanel here:
https://gitlab.com/pc88mxer/electronic-leadscrew/-/blob/2fc90ac54af3309fb0e042deee05f51e158d247f/els-f280049c/main.cpp#L59
so if you add your new function after that point you'll be able to access it.
-
Thanks to everyone for your help so far, with a little luck and a bit more help I might actually be able to get this working. I think I'm 90% there.
ledtester, I moved newFunction() to the bottom of main and it compiles and works perfectly :)
I will be adding a fair bit of code to this project and do not want to place it all at the bottom of main.
I tried and succeeded at moving newFunction() into the ControlPanel class as a public member (please correct me if my terminology is incorrect). This compiles and I was able to then call it from main like this:
controlPanel.newFunction(); and it works with the exception of one line of code that I had to comment out for the moment.
While the actual newFunction() was at the bottom of main.cpp, there was one function call that was working in newFunction() that no longer compiles when I moved it out of main and into the ControlPanel class.
The problematic line of code is this.... core.setPowerOn(core.isPowerOn());
I assume this works while actually in main.cpp because of this declaration near the beginning of main Core core(&encoder, &stepperDrive); I think this is the similar to a prototype declaration? except perhaps this is what causes the C++ compiler to create an instance of that object??? Is this correct?
AND since there is no such declaration of core in ControlPanel.cpp it does not know how to compile it, is that correct?
Further I can't simply declare core again in ControlPanel because that would be a new instance not the original, is that correct?
I think the good news is that the core member functions isPowerOn() and setPowerOn() are both in the public section of the core class. I'm just not sure how to access those functions while I'm in my newFunction() method within the ControlPanel class?
-
Please show us the code of newFunction.
If your function works when you put it in main.cpp why not just leave it there? It needs access to two objects to work, controlPanel and core, and if you define it in main.cpp it will have access to both of them.
You can define it in another file, but it complicates things and I don't think it's worth it in this case.
-
... it complicates things ...
isn't that the main purpose of C++ ;)
-
You could just pass a reference to core as an argument to newFunction():
class ControlPanel {
[...]
public:
void newFunction(Core &core);
};
This way you can call panel.newFunction(core) from main(), where you have core available. You will have to include Core.h in ControlPanel.h (I'm guessing at file names here) so the compiler knows what Core is.
It would be helpful if you posted your code.
-
You could just pass a reference to core as an argument to newFunction():
class ControlPanel {
[...]
public:
void newFunction(Core &core);
};
This way you can call panel.newFunction(core) from main(), where you have core available. You will have to include Core.h in ControlPanel.h (I'm guessing at file names here) so the compiler knows what Core is.
It would be helpful if you posted your code.
This seems like a good approach, however
public:
void newFunction(Core &core); <-- I get the compiler error "identifier "Core" is undefined" for this line that I added to ControlPanel.h
This is with #include "Core.h" in ControlPanel.h just under the other #includes for example SPIBus.h at the top of ControlPanel.h
#include "F28x_Project.h"
#include "SPIBus.h"
#include "Core.h" // new Oct 6
-
Look at the includes in main.cpp, where you previously used Core without compiler errors to see what else is included there. Also check to make sure Core is not inside a different namespace. Does your main program have "using namespace" anywhere? Is there a namespace in Core.h? If it is a namespace issue, you can change the function to:
class ControlPanel {
[...]
public:
void newFunction(mynamespace::Core &core);
};
Replace "mynamespace" above with the correct name for the namespace.
-
Ignore my previous reply. I downloaded the code and it is not a namespace issue. The problem is that Core.h includes ControlPanel.h. I don't see a reason why it is included, you can try to remove it from "Core.h" and see if that fixes it. If not, remove the #include "Core.h" from ControlPanel.h and instead just add the following line:
class Core;
You have to include "Core.h" in ControlPanel.cpp where you implement ControlPanel::newFunction();
-
Ignore my previous reply. I downloaded the code and it is not a namespace issue. The problem is that Core.h includes ControlPanel.h. I don't see a reason why it is included, you can try to remove it from "Core.h" and see if that fixes it. If not, remove the #include "Core.h" from ControlPanel.h and instead just add the following line:
class Core;
You have to include "Core.h" in ControlPanel.cpp where you implement ControlPanel::newFunction();
hubi,
THANK YOU..... adding class Core to ControlPanel.h did the trick
I would like to understand why.
1) I guess without class Core
the ControlPanel class and hence its member functions don't know anything about the Core class, and adding class Core
then provides that definition to ControlPanel?
2) Then when I call controlPanel.newFunction(core); in main it uses the actual instance "core" represented by the Core class, is that correct?
-
1) I guess without class Core
the ControlPanel class and hence its member functions don't know anything about the Core class, and adding class Core
then provides that definition to ControlPanel?
It's not so much that ControlPanel needs to know what Core is, but the compiler needs to know.
2) Then when I call controlPanel.newFunction(core); in main it uses the actual instance "core" represented by the Core class, is that correct?
Yes, it uses a reference to the instance of class Core.