Do virtual functions have to be public? - c++

Here is the way I have my base class working:
class AguiWidgetBase
{
//variables
AguiDockingEnum dockingStyle;
std::string text;
AguiRectangle clientRectangle;
AguiColor tintColor;
AguiColor fontColor;
std::map<int,int,CmpIntInt> children;
//private methods
void zeroMemory();
virtual void onPaint();
virtual void onAddChildControl(AguiWidgetBase *control);
virtual void onTintColorChanged(AguiColor color);
virtual void onDockingStyleChanged(AguiDockingEnum style);
virtual void onTextChanged(std::string text);
virtual void onThemeChanged(const AguiTheme &theme);
void (*onPaintCallback)(AguiRectangle clientRect);
void (*onTintColorChangedCallback)();
void (*onDockingStyleChangedCallback)();
void (*onTextChangedCallback)();
void (*onThemeChangedCallback)();
protected:
AguiWidgetBase *parentWidget;
public:
AguiWidgetBase(void);
~AguiWidgetBase(void);
void addChildControl(AguiWidgetBase *control);
void removeChildControl(AguiWidgetBase *control);
AguiWidgetBase* getParent();
void paint();
void setTintColor(AguiColor color);
AguiColor getTintColor();
void setDockingStyle(AguiDockingEnum style);
AguiDockingEnum getDockingStyle();
void setText(std::string text);
std::string getText();
void SetTheme( const AguiTheme &theme);
};
Some of them work like this. There is a regular non-overridable funcion which calls the virtual function and the function pointer if its not NULL.
Will my virtual functions be able to once again go into the private scope when I create derived classes or must they be public?
I want to avoid them being public due to my design.
Thanks

Virtual functions can have public, protected, or private access.
A discussion of them via the C++ FAQ.
Should I use protected virtuals instead of public virtuals?
When should someone use private virtuals?

They can be private and do not need to be public.

Though they can be public, it is not considered as good design principle as Herb Sutter says.

virtual functions can be private. This is because private means that the function cannot be called by derived classes. It does not prevent the entry to the v-table being overwritten. This means that the both the base class and the derived class will have access to the overwritten virtual function.

Related

How to "bypass" encapsulation?

The usual example with a unit.
class Unit {
private:
int health;
public:
Unit(int health);
virtual ~Unit();
protected:
virtual void setHealth(int newHealth);
}
next, make heir
class Healer : public Unit {
public:
Healer(int health);
virtual void healing(Unit* other);
};
In the implementation of healing
void Healer::healing(Unit* other) {
other->setHealth(100);
}
encapsulation does not allow doing so other-> setHealth (100);
'setHealth' is a protected member of 'Unit' other->setHealth(newHealth);
can only access this member on an object of type 'Healer' virtual void
setHealth(int newHealth);
In this case, you can call this method for "this".
P.S.: public method setHealth - do not offer. method healing for class Unit - do not offer.
As mentioned by #EekTheCat, you could use a friend.
Alternatively, you could add a function to receive health. You currently have a public function for setting health. You can just as easily add a public function for receiving health:
class Unit {
private:
int health;
public:
Unit(int health);
virtual ~Unit();
protected:
virtual void setHealth(int newHealth);
void acceptHealth();
}
void Unit::acceptHealth() {
health += 100;
}
You could create a new child class called the patient and implement the accept health as a virtual function of Unit, implemented by the patient class.
Your code is not complicated (thank you for keeping it minimal), but you could add tokens and security to pass around to ensure that health points are properly conserved according to rules that could be enforced in your virtual reality.

CRTP causing segfault

I have a pure virtual class Interface:
class Interface {
public:
virtual ~Interface() noexcept;
virtual void open()=0;
virtual void close()=0;
protected:
explicit Interface(const string params);
string params_;
}
I then have an abstract class where I implement my business logic:
template<typename T>
class AbstractInterface : public Interface {
public:
void open() override;
void close() override;
void read_is_complete(const vector<byte_array>);
protected:
explicit AbstractInterface(const string params);
virtual ~AbstractInterface() noexcept;
}
Then there is the implementation for the interface that uses CRTP for polymorphism:
class SPInterface : public AbstractInterface<SPInterface> {
public:
explicit SPInterface(const string params);
virtual ~SPInterface() noexcept;
void open();
void close();
void read_is_complete(const vector<byte_array> data);
}
I have a unit test where I create an instance of SPInterface:
unique_ptr<Interface> intf;
intf.reset(new SPInterface("aaa"));
Letting this get out of scope calls the destructor AbstractInterface which in turn calls the close method on AbstractInterface and then it segfaults on this:
template<typename T>
void AbstractInterface<T>::close() {
static_cast<T *>(this)->close();
params_ = "";
}
Which is confusing as I already created an instance of the class. lldb seems to confirm:
AbstractInterface<SPInterface>::close(this=<unavailable>)
Letting this get out of scope calls the destructor AbstractInterface which in turn calls the close method on AbstractInterface and then it segfaults on this:
template<typename T>
void AbstractInterface<T>::close() {
static_cast<T *>(this)->close();
params_ = "";
}
It seems that you are trying to invoke a method of a derived class from within the destructor of a base class.
This is not safe at all and a segfault is the way the executable has to tell you that it doesn't approve that. :-)
Even though CRTP allows you to invoke a member function that belongs to the derived class on a (let me say) living object, it doesn't change the way an object is destructed.
Do not forget that bases and members are destroyed in the reverse order of the completion of their constructor.

C++ Cannot convert child* to parent* by assignment

Using the following two classes...
//pure virtual...
class Monkey
{
public:
virtual ~Monkey(){}
virtual void clearMonkeys() = 0;
virtual std::shared_ptr<std::vector<sf::Text>> getMonkeyListPtr() = 0;
virtual void addMonkey(String message,Vector2f position,float depthValue) = 0;
};
class NullMonkey : public Monkey
{
public:
NullMonkey () {/*Do Nothing*/}
virtual ~NullMonkey () {/*Do Nothing*/}
virtual void clearMonkeys(){/*Do Nothing*/};
virtual std::shared_ptr<std::vector<sf::Text>> getMonkeyListPtr()
{
//Do Nothing but...
//Return NULL shared pointer
std::shared_ptr<std::vector<sf::Text>> nullSharedPointer;
return nullSharedPointer;
//Of course I am ASSUMING I will check for NULL pointer...
}
virtual void addMonkey(String message,Vector2f position,float depthValue){/*Do Nothing*/};
};
...I have issues when casting.
Specifically I am using these classes as static members and have a situation where if one class is not available I use the Null class to fall back on to prevent app crash. It also adds the ability to hot-swap child classes for debug purposes.
Unfortunately the following...
class ServLoc
{
public:
ServLoc();
static void initialize()
{
theMonkey = &theNullMonkey; //Error here
}
//...
static Monkey* theMonkey;
static NullMonkey theNullMonkey;
};
...throws 'cannot convert NullMonkey* to Monkey* in assignment'.
I should also add add I have defined the static members in the .cpp file
NullMonkey ServLoc::theNullMonkey;
Monkey* ServLoc::theMonkey;
The funny thing is I have used similar classes in similiar situations before and did not get this error. I am at a loss. It is probably something simple but still...
In fact I implement a log class using this method. It means I can hot-swap various forms of logging (including the null logger to disable logging) and have access to the logger wherever by just using the ServLoc static members...
class Logger
{
public:
virtual ~Logger() {}
virtual void log(const logType type,const char *message) = 0;
//...
};
class NullLogger : public Logger
{
public:
virtual ~NullLogger() {/*Do Nothing*/};
NullLogger() {/*Do Nothing*/};
virtual void log(const logType type,const char *message) {/*Do Nothing*/};
//...
};
This when used in same way in ServLoc as shown above works fine!?
Any ideas?
Regards
Edit - Fixed spelling mistakes
I suspect (could you clarify?), that you are calling the static function initialize() from another statically initialized class? Since this would all be done at program startup (and C++ does not guarantee any static initialization order between files), initialize may be called before ServLoc::theNullMonkey; has been constructed?!

enforce order of function calls?

Say I have a abstract base class and I want to have a pure virtual method which must be implemented by the derived class but I want to make sure that the derived method calls functions in a particular order what could I do to enforce it ?
I.E
base class
virtual void doABC()=0;
virtual void A()=0;
virtual void B()=0;
virtual void C()=0;
// must call ABC in the correct order
derived class public base
void doABC();
This is just so I have a better understanding on how to design my classes to enforce someone to use my class correctly.
You're looking for the template method pattern:
http://en.wikipedia.org/wiki/Template_method_pattern
Something along these lines:
class BaseAlgorithm
{
protected:
virtual void firstStep() = 0;
virtual void secondStep() = 0;
virtual void finalStep() = 0;
public:
void runAlgorithm()
{
firstStep();
secondStep();
finalStep();
}
};
class ConcreteAlgorithm : BaseAlgorithm
{
virtual void firstStep() {};
virtual void secondStep() {};
virtual void finalStep() {};
};
You basically force extending classes to implement all intermediate steps, but you keep them protected or private - document this - and only call runAlgorithm(), which ties the smaller pieces together.
There are actually two particular ways, depending on whether you go with inheritance or parameterization.
If you with inheritance, it is the Template Method pattern:
class Base {
public:
void doit() {
this->do1();
this->do2();
}
private:
virtual void do1() = 0;
virtual void do2() = 0;
};
And if you go with parameterization, it is the Strategy pattern:
class Strategy {
public:
virtual void do1() = 0;
virtual void do2() = 0;
};
void doit(Strategy& s) {
s.do1();
s.do2();
}
From the website:
Strategy is like Template Method except in its granularity. [Coplien, C++ Report, Mar 96, p88]
Template Method uses inheritance to vary part of an algorithm. Strategy uses delegation to vary the entire algorithm. [GoF, p330]
Strategy modifies the logic of individual objects. Template Method modifies the logic of an entire class. [Grand, p383]
I recommend you familiarize yourself with them.
The simplest answer could be if You remove virtual from doABC(), so that it can not be derived by child class. Call the virtual methods inside doABC() in correct order.

How can I resolve interface method and base class method name conflict in C++ Builder?

I have the following abstract base class, SettingsInterface, that I use as an interface:
class SettingsInterface
{
public:
virtual void Refresh() = 0;
virtual void Update() = 0;
virtual void OnConnect() = 0;
virtual void OnDisconnect() = 0;
};
I'm trying to implement this interface in my class below, which inherits from TFrame. TFrame inherits from another class that also has a virtual method called Update.
class DebugSettingsFrame : public TFrame, public SettingsInterface
{
//a bunch of IDE-managed components - left out for brevity
public:
virtual void Refresh();
virtual void Update();
virtual void OnConnect();
virtual void OnDisconnect();
};
When I compile this, I get the error virtual function DebugSettingsFrame::Update() conflicts with base class 'TWinControl'.
I'm stomped on this. How can I resolve this without changing my interface's method definition, Update, to something else?
Edit - Follow-up:
So C++ doesn't have a construct similar to C# where you can explicitly implement interface methods that have the same definition?
Thanks!
Try something like (from the code I can't say exactly):
DebugSettingsFrame::TFrame::Update();
:: is the scope resolution operator. You should be able to specify precisely which version of the function you are calling.
However, note that this is a symptom of a design that may be getting too complex.