> s this legal? (For example, can I set a GUIComponent as the return of a function and instead return a subclass?)
Yes. For example:
GUIComponent* getComponent() { return new TextLabel( /* ... */ )
is fine, providedTextLabel is a derived class of GUIComponent.
> Why is the compiler complaining?
The compile-time type of the result of the function is a pointer to GUIComponent (though the run-time of the pointed object might be TextLabel). And the compiler cannot see a member-function getFont() in GUIComponent.
> What would work?
A simple way would be to perform a type-safe run-time down-cast to TextLabel and call getFont() on the result of the cast. For example:
GUIComponent* gui_component = guiList[0]->getComponent(1) ;
TextLabel* text_label = dynamic_cast<TextLabel*>(gui_component) ;
if( text_label != nullptr )
{
// use text_label
auto font = text_label->getFont() ;
// etc
}
else
{
// this component is not a TextLabel
}
See: http://www.bogotobogo.com/cplusplus/dynamic_cast.php
vijayan121
Posting Virtuoso
1,606 posts since Dec 2006
Reputation Points: 1,159
Solved Threads: 287
> for this to work the base class, here GUIComponent, must have a virtual function -
> since mine doesn't need it, I just shut down the error with ...
You need a virtual destructor; C++ requires that a class having a virtual function must have a virtual destructor. Even if there was no dynamic_cast and no other virtual functions, you would still require a virtual destructor if you do something like this:
std::vector<GUIComponent*> components ;
components.push_back( new TextLabel( /*...*/ ) ) ; // etc
// use the vector
// ...
// finaly clean up
// the correct destructor (and operator delete) must be called here.
for( component* c : components ) delete c ;
Consider using smart pointers instead of raw pointers whenever clean up is required; for instance ifGUIComponent objects were dynamically allocated with new.
std::vector< std::unique_ptr > or std::vector< std::shared_ptr > would take care of resource management. See:
http://www.devx.com/cplus/10MinuteSolution/28347/0/page/1
http://www.devx.com/cplus/10MinuteSolution/39071/1954
Smart pointers are handy whenever acquisition and release of resources are an issue - for example when using a C-library (may be SDL) with low-level facilities (sandwich functions) for resource management. For example:
void function( /*...*/ ) // pseudocode
{
// ... ;
std::shared_ptr<std::FILE> file( std::fopen( __FILE__, "r" ), std::fclose ) ;
// the destructor of shared_ptr will call std::fclose
// ...
foo( /* ... */ ) ; // safe evn if foo throws; file will be closed
// ...
if( nothing_more_2b_done ) return ; // safe: file will be closed
// ...
int c ;
while( ( c = std::fgetc( file.get() ) ) != EOF ) std::cout << char(c) ;
throw "something" ; // safe: file will be closed
// ...
// normal return : file will be closed
}
vijayan121
Posting Virtuoso
1,606 posts since Dec 2006
Reputation Points: 1,159
Solved Threads: 287