C++ programming How to access a variable from outside - Page 1
Forum section: electronics / general

author: Jester
author_rank: Frequent Contributor
timestamp: October 04, 2022, 07:51:28 pm
content: I can generally follow conventional C code, but get pretty lost with C++, hopefully my terminology is close enough to convey my questionAssume 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 feedLED_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 offleds.all = 0;}return leds;}

author: ataradov
author_rank: Super Contributor
timestamp: October 04, 2022, 07:59:22 pm
content: "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".

author: ledtester
author_rank: Super Contributor
timestamp: October 04, 2022, 08:12:15 pm
content: 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.

author: Jester
author_rank: Frequent Contributor
timestamp: October 04, 2022, 08:21:31 pm
content: Quote from: ataradov on October 04, 2022, 07:59:22 pmIn main.cpp before main() we have:FeedTableFactory feedTableFactory;UserInterface userInterface(&controlPanel, &core, &feedTableFactory);In UserInterface.cpp we have the followingUserInterface :: UserInterface(ControlPanel *controlPanel, Core *core, FeedTableFactory *feedTableFactory){this->controlPanel = controlPanel;this->core = core;this->feedTableFactory = feedTableFactory;this->metric = false; // start out with imperialthis->thread = false; // start out with feedsthis->reverse = false; // start out going forwardthis->feedTable = NULL;this->keys.all = 0xff;// initialize the core so we start up correctlycore->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();}

author: mushroom
author_rank: Regular Contributor
timestamp: October 04, 2022, 08:24:38 pm
content: Impossible to answer, unless you provide the classes definitions, and their inheritance(s) !

author: Jester
author_rank: Frequent Contributor
timestamp: October 04, 2022, 08:33:06 pm
content: Quote from: mushroom on October 04, 2022, 08:24:38 pmDo 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 BusSPIBus *spiBus;// Current RPM value; 4 decimal digitsUint16 rpm;// Current displayed setting value, 4 digitsconst Uint16 *value;// Current LED statesLED_REG leds;// current key statesKEY_REG keys;// number of times current key state has been seenKEY_REG stableKeys;Uint16 stableCount;// current override message, or NULL if noneconst Uint16 *message;// brightness, levels 1-8, 0=offUint16 brightness;// Derived state, calculated internallyUint16 sevenSegmentData;// dummy register, for SPIUint16 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 operationvoid initHardware(void);// poll the keys and return a maskKEY_REG getKeys(void);// set the RPM value to displayvoid setRPM(Uint16 rpm);// set the value to displayvoid setValue(const Uint16 *value);// set the LED statesvoid setLEDs(LED_REG leds);// set a message that overrides the display, 8 characters requiredvoid setMessage(const Uint16 *message);// set a brightness value, 0 (off) to 8 (max)void setBrightness(Uint16 brightness);// refresh the hardware displayvoid refresh(void);};

author: mushroom
author_rank: Regular Contributor
timestamp: October 04, 2022, 08:37:17 pm
content: Not really, as many information is missing.But it seems you are attempting to access a private member from outside.

author: ledtester
author_rank: Super Contributor
timestamp: October 04, 2022, 08:37:46 pm
content: Based on:Code:UserInterface userInterface(&controlPanel, &core, &feedTableFactory);I would try in main() something like:Code: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 functionloadFeedTable()might do this for you if thegetFeedTable()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().

author: ataradov
author_rank: Super Contributor
timestamp: October 04, 2022, 08:41:13 pm
content: 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.

author: mikerj
author_rank: Super Contributor
timestamp: October 04, 2022, 08:45:42 pm
content: Quote from: Jester on October 04, 2022, 08:21:31 pmThe 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()->ledsIs this the Clough42 electronic feedscrew project?

author: langwadt
author_rank: Super Contributor
timestamp: October 04, 2022, 08:54:55 pm
content: Quote from: mikerj on October 04, 2022, 08:45:42 pmlooks like ti,https://github.com/clough42/electronic-leadscrew

author: Jester
author_rank: Frequent Contributor
timestamp: October 04, 2022, 08:57:20 pm
content: Quote from: mikerj on October 04, 2022, 08:45:42 pmYes this is the C42 projectCan you please explain the precise syntax for "feedTableFactory.current()->leds"I tried LED_REG leds = feedTableFactory.current()->leds; // compiler error is no member currentalso tried LED_REG leds = feedTableFactory->current()->leds; // compiler error expression must have pointer typeI did notice that in the public section of the ControlPanel class that this function existsvoid setLEDs(LED_REG leds)and alsoKEY_REG getKeys(void);however I need getLEDs

author: ledtester
author_rank: Super Contributor
timestamp: October 04, 2022, 09:44:07 pm
content: Quote from: Jester on October 04, 2022, 08:57:20 pmTo add a getLEDs() method you can modify ControlPanel.h as indicated here:https://gitlab.com/pc88mxer/electronic-leadscrew/-/commit/2fc90ac54af3309fb0e042deee05f51e158d247f?w=1Complete file:https://gitlab.com/pc88mxer/electronic-leadscrew/-/blob/2fc90ac54af3309fb0e042deee05f51e158d247f/els-f280049c/ControlPanel.h

author: Jester
author_rank: Frequent Contributor
timestamp: October 04, 2022, 10:13:23 pm
content: Quote from: ledtester on October 04, 2022, 09:44:07 pmledtester thank youI added your code to ControlPanel.h and it compiles.I'm having trouble with syntax in main.cppI tried LED_REG leds = controlPanel->getLEDs(); // error expression must have pointer type

author: ledtester
author_rank: Super Contributor
timestamp: October 04, 2022, 10:31:09 pm
content: Try:Code:LED_REG leds = controlPanel.getLEDs();controlPanel is probably not a pointer -- hence the use of "."

author: Jester
author_rank: Frequent Contributor
timestamp: October 04, 2022, 10:34:32 pm
content: Quote from: ledtester on October 04, 2022, 10:31:09 pmIt's working. Thanks so much!

author: radiolistener
author_rank: Super Contributor
timestamp: October 06, 2022, 02:17:30 pm
content: Quote from: Jester on October 04, 2022, 07:51:28 pmin 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).

author: Jester
author_rank: Frequent Contributor
timestamp: October 06, 2022, 06:22:15 pm
content: Quote from: radiolistener on October 06, 2022, 02:17:30 pmI 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 works3a) 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?

author: ledtester
author_rank: Super Contributor
timestamp: October 06, 2022, 06:35:18 pm
content: Quote from: Jester on October 06, 2022, 06:22:15 pmWhere 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:Code:inline LED_REG ControlPanel :: getLEDs(){return leds;}

author: Jester
author_rank: Frequent Contributor
timestamp: October 06, 2022, 06:41:15 pm
content: Quote from: ledtester on October 06, 2022, 06:35:18 pmI 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 insidevoid( ControlPanel :: newFunction(void)?I tried it and it compiles, looks like I just wrote my first C++ member function testing..... I shall return.

author: ledtester
author_rank: Super Contributor
timestamp: October 06, 2022, 06:53:53 pm
content: 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#L59so if you add your new function after that point you'll be able to access it.

author: Jester
author_rank: Frequent Contributor
timestamp: October 06, 2022, 08:54:40 pm
content: 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 perfectlyI 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 mainCore 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?

author: ledtester
author_rank: Super Contributor
timestamp: October 06, 2022, 09:38:50 pm
content: 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.

author: langwadt
author_rank: Super Contributor
timestamp: October 06, 2022, 09:45:15 pm
content: Quote from: ledtester on October 06, 2022, 09:38:50 pmisn't that the main purpose of C++

author: hubi
author_rank: Regular Contributor
timestamp: October 06, 2022, 10:50:25 pm
content: You could just pass a reference to core as an argument to newFunction():Code: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.

author: Jester
author_rank: Frequent Contributor
timestamp: October 07, 2022, 02:51:07 pm
content: Quote from: hubi on October 06, 2022, 10:50:25 pmThis seems like a good approach, howeverpublic:void newFunction(Core &core); <-- I get the compiler error "identifier "Core" is undefined" for this line that I added to ControlPanel.hThis is with #include "Core.h" in ControlPanel.h just under the other #includes for example SPIBus.h at the top of ControlPanel.hCode:#include "F28x_Project.h"#include "SPIBus.h"#include "Core.h" // new Oct 6Code:

author: hubi
author_rank: Regular Contributor
timestamp: October 07, 2022, 03:20:58 pm
content: 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:Code:class ControlPanel {[...]public:void newFunction(mynamespace::Core &core);};Replace "mynamespace" above with the correct name for the namespace.

author: hubi
author_rank: Regular Contributor
timestamp: October 07, 2022, 03:35:21 pm
content: 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:Code:class Core;You have to include "Core.h" in ControlPanel.cpp where you implement ControlPanel::newFunction();

author: Jester
author_rank: Frequent Contributor
timestamp: October 07, 2022, 05:46:34 pm
content: Quote from: hubi on October 07, 2022, 03:35:21 pmhubi,THANK YOU.....adding class Core to ControlPanel.h did the trickI would like to understand why.1) I guess withoutCode:class Corethe ControlPanel class and hence its member functions don't know anything about the Core class, and addingCode:class Corethen 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?

author: hubi
author_rank: Regular Contributor
timestamp: October 07, 2022, 06:41:05 pm
content: Quote from: Jester on October 07, 2022, 05:46:34 pmIt's not so much that ControlPanel needs to know what Core is, but the compiler needs to know.Quote from: Jester on October 07, 2022, 05:46:34 pmYes, it uses a reference to the instance of class Core.