AggrorJorn Posted May 29, 2012 Share Posted May 29, 2012 I have a list of GUI elements. GUI elements like button, checkbox etc inherit from a base GUI class. The list is of the base Type: vector<LCPGui*> mainMenuElements; The elements added are checkboxes and buttons. Via a for loop I want to call their respective draw functions: for(int i = 0; i < mainMenuElements.size(); i++) mainMenuElements.at(i)->Draw(); The Draw function that is being called, resides in the GUI class, whiles I need the Draw function from the sub classes. 1 way to solve this would be to add the 'virtual' keyword to the Draw function in the base class. However sometimes I need to use the base class Draw function. How can I call the Draw function from the subclasses? Quote Link to comment Share on other sites More sharing options...
Canardia Posted May 29, 2012 Share Posted May 29, 2012 GUI::Draw(); When this is used inside a child class, it doesn't need to be a static method, but it will actually call the instanced base class' method (which is kinda not instanced alone, but fusioned into one instanced with the child class). Quote ■ Ryzen 9 ■ RX 6800M ■ 16GB ■ XF8 ■ Windows 11 ■ ■ Ultra ■ LE 2.5 ■ 3DWS 5.6 ■ Reaper ■ C/C++ ■ C# ■ Fortran 2008 ■ Story ■ ■ Homepage: https://canardia.com ■ Link to comment Share on other sites More sharing options...
AggrorJorn Posted May 29, 2012 Author Share Posted May 29, 2012 So it is kinda like how constructors work? It first executes the base class and then goes to the next child class? Quote Link to comment Share on other sites More sharing options...
Canardia Posted May 29, 2012 Share Posted May 29, 2012 Doesn't matter if it's at the beginning or somewhere else in the method, but yeah, usually it's in the beginning because of practical reasons, that the coder wants the base class done first and then only add his own stuff to it. Your question is a bit wierd, so I'm not sure if you understood my first answer. What I meant is that you have a child class method like this: class GUI { public: void Draw() { DrawBox(); } }; class MyChild : public GUI { public: void Draw() { GUI::Draw(); DrawCircle(); } }; Quote ■ Ryzen 9 ■ RX 6800M ■ 16GB ■ XF8 ■ Windows 11 ■ ■ Ultra ■ LE 2.5 ■ 3DWS 5.6 ■ Reaper ■ C/C++ ■ C# ■ Fortran 2008 ■ Story ■ ■ Homepage: https://canardia.com ■ Link to comment Share on other sites More sharing options...
Roland Posted May 29, 2012 Share Posted May 29, 2012 class GUI { public: virtual void Draw() // important ... virtual must be here { // do your base things } }; class CheckBox : pubic GUI { public: void Draw() { GUI::Draw(); // base class GUI::Draw is executed // Do you specialized drawing here } }; ///////// using ///// void example() { std::vector<GUI*> guis ; guis.push_back( new CheckBox() ); guis.push_back( new CheckBox() ); guis.push_back( new CheckBox() ); // draw them for( std::vector<GUI*>::iterator it = guis.begin(); it != guis.end(); it++ ) (*it)->Draw() // another way to draw them std::for_each( guis.begin(), guis.end(), [ ](GUI* pGui) { pGui->Draw(); }); // .... // .... // .... // .... Quote Roland Strålberg Website: https://rstralberg.com Link to comment Share on other sites More sharing options...
Canardia Posted May 29, 2012 Share Posted May 29, 2012 You are wrong Roland. Virtual is never needed in C++, and it only creates bloated and slow code. I just tried this example and it works fine, it prints: Cow Horse #include <cstdio> class GUI { public: void Draw() { printf("Cown"); } }; class Child : public GUI { public: void Draw() { GUI::Draw(); printf("Horsen"); } }; int main() { Child tia; tia.Draw(); } Quote ■ Ryzen 9 ■ RX 6800M ■ 16GB ■ XF8 ■ Windows 11 ■ ■ Ultra ■ LE 2.5 ■ 3DWS 5.6 ■ Reaper ■ C/C++ ■ C# ■ Fortran 2008 ■ Story ■ ■ Homepage: https://canardia.com ■ Link to comment Share on other sites More sharing options...
AggrorJorn Posted May 29, 2012 Author Share Posted May 29, 2012 Thanks for the answers guys. I haven't explained it good enough: When I use the draw function in the loop, I purely want to call the Draw function of that object type. So the draw function of the button/checkbox. I Don't want to use the Draw function from the base class. Perhaps this is not possible. If so, then I need to rearange some code and make the base class Draw function empty and add virtual to it. @Metatron, Yes this works, but here you define tia as a Child and not as a Horse. The list exists out of base elements but the actual items are sub elements. Quote Link to comment Share on other sites More sharing options...
Roland Posted May 29, 2012 Share Posted May 29, 2012 You are wrong Roland. Virtual is never needed in C++, and it only creates bloated and slow code. Of course I'm not wrong. You are only showing that you don't understand the idea with virtual Listen to Aggror He's got it. Quote Roland Strålberg Website: https://rstralberg.com Link to comment Share on other sites More sharing options...
Roland Posted May 29, 2012 Share Posted May 29, 2012 Thanks for the answers guys. I haven't explained it good enough: When I use the draw function in the loop, I purely want to call the Draw function of that object type. So the draw function of the button/checkbox. I Don't want to use the Draw function from the base class. Perhaps this is not possible. If so, then I need to rearange some code and make the base class Draw function empty and add virtual to it. @Metatron, Yes this works, but here you define tia as a Child and not as a Horse. The list exists out of base elements but the actual items are sub elements. OK. The change is simple enough to make that happen class GUI { public: virtual void Draw() = 0; // important ... virtual must be here // = 0 means that its abstract with no code }; class CheckBox : pubic GUI { public: void Draw() { // Do you specialized drawing here } }; ///////// using ///// void example() { std::vector<GUI*> guis ; guis.push_back( new CheckBox() ); guis.push_back( new CheckBox() ); guis.push_back( new CheckBox() ); // draw them for( std::vector<GUI*>::iterator it = guis.begin(); it != guis.end(); it++ ) (*it)->Draw() // another way to draw them std::for_each( guis.begin(), guis.end(), [ ](GUI* pGui) { pGui->Draw(); }); // .... // .... // .... // .... Quote Roland Strålberg Website: https://rstralberg.com Link to comment Share on other sites More sharing options...
Canardia Posted May 29, 2012 Share Posted May 29, 2012 You can make seperate lists for each class, that works fine, and makes faster code. Then you have can have one method which loops through all the class lists. Also for memory allocation you should never use "new" or "malloc"; but always "alloca", because it uses fast linear stack memory and not slow fragmented heap memory. Quote ■ Ryzen 9 ■ RX 6800M ■ 16GB ■ XF8 ■ Windows 11 ■ ■ Ultra ■ LE 2.5 ■ 3DWS 5.6 ■ Reaper ■ C/C++ ■ C# ■ Fortran 2008 ■ Story ■ ■ Homepage: https://canardia.com ■ Link to comment Share on other sites More sharing options...
Furbolg Posted May 29, 2012 Share Posted May 29, 2012 You also can use assembler which is even faster.... listen to Roland, thats the right way. Metatron is right about speed but its not that big impact like he did like to tell you. Quote Link to comment Share on other sites More sharing options...
AggrorJorn Posted May 29, 2012 Author Share Posted May 29, 2012 Okay, thanks for the help. I will use a virtual function and move the code that is inside the Draw function from the Base. Quote Link to comment Share on other sites More sharing options...
Canardia Posted May 29, 2012 Share Posted May 29, 2012 Assembler is not cross-platform, and with normal coding, it's also slower than C/C++, because the compilers do insane optimizations which nobody can do by hand in assembler. Speed was an issue earlier, then there were times when PCs were fast (when Doom3 came out, and then again when Crysis 1 came out), and now they are slow again, because everyone buys the cheapest laptop they can get, so speed IS an issue. It's the game industry which dictates what PCs are sold. If nobody makes AAA games, nobody produces AAA PCs; and not the other way around. Here's a realistic example. I am normal customer who wants to play BF3, so I go to a computer shop and ask for a PC which can run this game well. I also want to play with my friends in the new AAA MMO, so the computer should run that too. Then I get an AAA PC, and the number of low end PCs goes down by 1 on the global market. I remember when we had like 50 people in our WoW guild, and they had the highest spec AAA PCs because playing WoW was very important to them, because all IRL friends played it too (and nobody had time for facebook because of the raiding and forum tactics topics), and they didn't want to lose some hard earned epix because of slow graphics or sluggish computer. Today all IRL friends are on facebook, and play facebook games, so nobody buys AAA PCs anymore. So facebook killed the AAA PCs, and PC gaming. Now facebook even wants to kill AAA phones too, by making their own iPhone clone. They already hired a bunch of Apple employees, which I heard on rock radio today. Quote ■ Ryzen 9 ■ RX 6800M ■ 16GB ■ XF8 ■ Windows 11 ■ ■ Ultra ■ LE 2.5 ■ 3DWS 5.6 ■ Reaper ■ C/C++ ■ C# ■ Fortran 2008 ■ Story ■ ■ Homepage: https://canardia.com ■ Link to comment Share on other sites More sharing options...
AggrorJorn Posted May 29, 2012 Author Share Posted May 29, 2012 Another Questions about this: How to define them when using headers? My header has: virtual void Draw(); and my CPP has virtual void Draw() = 0; although I do not get any errors during coding, the compiler sees it as a unresolved external. Quote Link to comment Share on other sites More sharing options...
Canardia Posted May 29, 2012 Share Posted May 29, 2012 You can't declare virtual methods in the cpp file, they work only in headers. It's like somekind of religion, totally fake. So you must put all the code into the header, or go back to my gnostic method of programming fast programs. Quote ■ Ryzen 9 ■ RX 6800M ■ 16GB ■ XF8 ■ Windows 11 ■ ■ Ultra ■ LE 2.5 ■ 3DWS 5.6 ■ Reaper ■ C/C++ ■ C# ■ Fortran 2008 ■ Story ■ ■ Homepage: https://canardia.com ■ Link to comment Share on other sites More sharing options...
Mumbles Posted May 29, 2012 Share Posted May 29, 2012 Roland has described exactly what you want, although it's described in a little more detail here. http://www.cplusplus.com/doc/tutorial/polymorphism/ It's the final section of that page in particular that you should read "Abstract base classes", but I would recommend reading the entire page from top to bottom... Quote LE Version: 2.50 (Eventually) Link to comment Share on other sites More sharing options...
Roland Posted May 29, 2012 Share Posted May 29, 2012 GUI.H ============ #pragma once class GUI { virtual void Draw( ) = 0; }; CHECKBOX.H ============ #pragma once #include "GUI.H" class CheckBox: public GUI { public: void Draw(); }; CHECKBOX.CPP =================== #include "CheckBox.h" void CheckBox::Draw() { // Draw here } Quote Roland Strålberg Website: https://rstralberg.com Link to comment Share on other sites More sharing options...
Rick Posted May 29, 2012 Share Posted May 29, 2012 @Aggror I generally put virtual in the derived class header but you don't have to. For me it just reminds me at a glance that it's overriding that method from the parent. Quote Link to comment Share on other sites More sharing options...
AggrorJorn Posted May 29, 2012 Author Share Posted May 29, 2012 Perfect! Thanks for the input everyone! Quote Link to comment Share on other sites More sharing options...
Furbolg Posted May 29, 2012 Share Posted May 29, 2012 Here is a link, there are some tests about how "slow" virtual functions really are. http://stackoverflow.com/questions/449827/virtual-functions-and-performance-c On modern CPUs its so fast that you will "feel" a difference at round about 1 million calls. You can create a whole engine with virtual functions (which is good to hide implementation specific details but i won't write all with virtual functions for example vector3 or matrix etc.) and its run without problems, because to load/draw a model is much (very much) slower then calling virtual functions. Quote Link to comment Share on other sites More sharing options...
Canardia Posted May 29, 2012 Share Posted May 29, 2012 Every bit counts. And 1 million iterations is quite low because I usually make speed tests with 10 billion iterations to get a worthy difference. Anyway, I'm not concerned about little speed differences at all, especially if they don't matter to the user at all. It's more a question of the path of decision. When I test something, then I use the results to show the right path for my decision. And then I stay on that decision, because it is a tested decision. Kinda like Zen programming Quote ■ Ryzen 9 ■ RX 6800M ■ 16GB ■ XF8 ■ Windows 11 ■ ■ Ultra ■ LE 2.5 ■ 3DWS 5.6 ■ Reaper ■ C/C++ ■ C# ■ Fortran 2008 ■ Story ■ ■ Homepage: https://canardia.com ■ Link to comment Share on other sites More sharing options...
Naughty Alien Posted May 29, 2012 Share Posted May 29, 2012 Assembler is not cross-platform, and with normal coding, it's also slower than C/C++, because the compilers do insane optimizations which nobody can do by hand in assembler. ..ill think twice about that..and also, remember that compiler is nothing but handwritten code.. 1 Quote Link to comment Share on other sites More sharing options...
Canardia Posted May 29, 2012 Share Posted May 29, 2012 ..ill think twice about that..and also, remember that compiler is nothing but handwritten code.. Handwritten yes, but handwritten by many people. A single people can not do such optimizations by hand in assembler. Unless he writes a assembler optimizing language, which C and FORTRAN was made for - to have a faster assembler than hand written by a single person. Quote ■ Ryzen 9 ■ RX 6800M ■ 16GB ■ XF8 ■ Windows 11 ■ ■ Ultra ■ LE 2.5 ■ 3DWS 5.6 ■ Reaper ■ C/C++ ■ C# ■ Fortran 2008 ■ Story ■ ■ Homepage: https://canardia.com ■ Link to comment Share on other sites More sharing options...
Guest Red Ocktober Posted May 29, 2012 Share Posted May 29, 2012 question for the theoretical purist and everyone else... do you'all consider it bad practice to have a virtual method actually do something... i mean, since by it's very nature it's designed merely to serve as a "placeholder" or "template" to be overridden? thx --Mike Quote Link to comment Share on other sites More sharing options...
Furbolg Posted May 30, 2012 Share Posted May 30, 2012 Virtual isn't just a "placeholder" or "template" and it can (but has not to) be overridden. In my opinion, the strength of virtual methods is that you can decide which method to use (base, derived) or to define that an specific method has to be implemented by user ( = 0 ). And you can also hide informations from the user. For example my actual engine iteration has something like this: (pseudo code, does not compile) class IRenderDevice { public: virtual void Initialise(u16 Width, u16 Height, u8 Bits) = 0; virtual void Draw(...) = 0; virtual void Terminate() = 0; }; class D3D9RenderDevice : public IRenderDevice { private: //some dx9 vars LPDIRECT3D9* d3d9; LPDIRECT3DDEVICE9* d3d9device; public: virtual void Initialise(u16 Width, u16 Height, u8 Bits); virtual void Draw(...); virtual void Terminate(); }; And this is how to use it: int main(int argc, char** argv) { IRenderDevice* mydevice = new D3D9Device(); mydevice->Initialise(800,600,32); // mainloop while(true) { mydevice->Draw(.....); } mydevice->Terminate(); }; So whats the advantage of this ? I just change "new D3D9Device();" with "new OpenGL33Device();" and it uses OpenGL 3.3. To be honest, this is not the full implementation and style but you should get the idea behind this In my real code the instances are created by a core class (you can call it factory) and the user of the "engine" has no worries but using directx / opengl by himself. He just uses my interface and classes i provide him. Of course he could write his own RenderDevice by inheritancing my IRenderDevice and create an instance by himself "new myogrerenderer();" etc. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.