I have complex parent class which is being inherited. For now I need just to override a handful of its functions and would like to prevent somehow the possibility to call some non-overridden functions of the parent class in the child object (these functions from parent class would not work properly). I would define them later, if necessary, just want to make it clear, that for now they are not usable, but still inherit some functions to make polymorphism possible. Is it possible to achieve it? Or do I need to change the design?
Here is a small example:
class ParentClass
{
public:
virtual void write() { ... }
virtual void read() { ... }
virtual void calculate() { ... }
};
class ChildClass : public ParentClass
{
public:
void calculate() override { ... }
};
I would like to prevent the possibility to call read or write functions from the ChildClass object, because these functions are complex to define and I don't need them right now. But at the same time I would like to prevent someone from using parent inherited functions in ChildClass. What is important, Parent class is defined in the 3rd party library and I cannot change the parent class.
My (clumsy) idea was to override these functions and throw in them to make it obvious, that they are not accessible, but it is so far from proper design... What could be the proper solution?
One approach when e.g. you want to use part of a class to implement a new class, and you want to use inheritance, but you don't want to expose the whole API of the base class, is to use private inheritance, and then pick and choose what you want to forward.
Here's an example:
#include <stdio.h>
class ParentClass
{
public:
virtual void write() { printf("write"); }
virtual void read() { printf("read"); }
virtual void calculate() { printf("calculate"); }
virtual void other() { printf("other"); }
};
class ChildClass : private ParentClass
{
public:
void calculate() override { printf("new calculate"); }
using ParentClass::other;
};
int main() {
ChildClass c;
c.calculate();
c.other();
}
In godbolt compiler explorer I get this generated assembly (as expected)
.LC0:
.string "new calculate"
.LC1:
.string "other"
main:
sub rsp, 8
mov edi, OFFSET FLAT:.LC0
xor eax, eax
call printf
mov edi, OFFSET FLAT:.LC1
xor eax, eax
call printf
xor eax, eax
add rsp, 8
ret
The using ParentClass::other syntax (for forwarding a function from the base class without changes) is C++11 only, you didn't tag the function c++11 so I don't know if you can use that :), but it is handy
Never had to code something like that and I can't at the moment try this solution out, so take this with a grain of salt.
I think you can declare them as deleted in the child class while keeping them virtual in the base class. This should prompt a compile time error when you try to use it on an object from a child class. That is, in the child class:
void write = deleted;
void read = deleted;
Unfortunately, I'm not 100% sure this would work on a virtual function. If not, you can also try to remove the virtual keyword from those functions in the parent class and use plain overload in the child class with deleted functions as above or even simply declare them without defining them (I prefer deleted functions as they are more explicit). Again, this should prompt a compile time error. You would of course lose the advantage of polymorphism, though.
Let me know if these solutions work.
Related
I am aware of the lack of reflection and basic template mechanics in C++ so the example below can't work. But maybe there's a hack to achieve the intended purpose in another way?
template <typename OwnerClass>
struct Template
{
OwnerClass *owner;
};
struct Base
{
virtual void funct ()
{
Template <decltype(*this)> temp;
// ...
}
};
struct Derived : public Base
{
void whatever ()
{
// supposed to infer this class and use Template<Derived>
// any chance some macro or constexpr magic could help?
funct();
}
};
In the example, Derived::whatever() calls virtual method Base::funct() and wants it to pass its own class name (Derived) to a template. The compiler complains "'owner' declared as a pointer to a reference of type 'Base &'". Not only does decltype(*this) not provide a typename but a reference, the compiler also can't know in advance that funct is called from Derived, which would require funct() to be made a template.
If funct() was a template however, each derived class needs to pass its own name with every call, which is pretty verbose and redundant.
Is there any hack to get around this limitation and make calls to funct() infer the typename of the calling class? Maybe constexpr or macros to help the compiler infer the correct type and reduce verbosity in derived classes?
You should use CRTP Pattern (Curiously Recurring Template Pattern) for inheritance.
Define a base class:
struct CBase {
virtual ~CBase() {}
virtual void function() = 0;
};
Define a prepared to CRTP class:
template<typename T>
struct CBaseCrtp : public CBase {
virtual ~CBaseCrtp() {}
void function() override {
using DerivedType = T;
//do stuff
}
};
Inherit from the CRTP one:
struct Derived : public CBaseCrtp<Derived> {
};
It should work. The only way to know the Derived type is to give it to the base!
Currently, this can't be done. Base is a Base and nothing else at the time Template <decltype(*this)> is instantiated. You are trying to mix the static type system for an inheritance hierarchy inherently not resolved before runtime. This very same mechanism is the reason for not calling virtual member functions of an object during its construction.
At some point, this limitation might change in the future. One step towards this is demonstrated in the Deducing this proposal.
I know that additional initialization methods are evil, as they leave a very nasty option for having object half-constructed and as result all methods needs to check for this. But what about this situation?
class config;
class cfg_item final
{
private:
friend class config;
cfg_item(std::weak_ptr<config> owner) : owner(owner) { }
std::weak_ptr<config> owner;
}
class config final : private std::enable_shared_from_this<config>
{
public:
config()
{
items.emplace(std::make_shared<cfg_item>(weak_from_this())); // Will crash!
}
private:
std::vector<std::shared_ptr<cfg_item>> items;
}
int main(int argc, char * argv[])
{
std::shared_ptr<config> cfg = std::make_shared<config>();
}
I KNOW WHY IT CRASHES. The std::shared_ptr in the main is not yet initialized with shared pointer to config instance, so constructor does not know how to make weak_from_this and just raises std::bad_weak_ptr exception because there are no valid std::shared_ptr pointing to this at constructor's call time.
The question is: how can I avoided the whole thing? I believe the only way I see would be to add separate initialization method, which is evil as I've already mentioned...
As note about real code: the constructors loads cfg_item from external source. It is assumed that all cfg_items are available for the entire lifetime of config. The weak pointers back to config are mandatory, as cfg_item must push all changes done to it back to config to save to external source
If you look at the answers to this question, there are strong arguments why an external initialization function is necessary. However, you rightfully write
I know that additional initialization methods are evil, as they leave a very nasty option for having object half-constructed and as result all methods needs to check for this.
it's possible to reduce this problem. Say you have a class foo, with the protocol that each time a foo object is constructed, foo::init() needs to be called. Obviously, this is a brittle class (client code will eventually omit calls to init()).
So, one way is to make the (non-copy / non-move) constructors of foo private, and create a variadic static factory method that creates objects, then calls init():
#include <utility>
class foo {
private:
foo() {}
foo(int) {}
void init() {}
public:
template<typename ...Args>
static foo create(Args &&...args) {
foo f{std::forward<Args>(args)...};
f.init();
return f;
}
};
In the following code
template<typename ...Args>
static foo create(Args &&...args) {
foo f{std::forward<Args>(args)...};
f.init();
return f;
}
note that this single method can be used for all constructors, regardless of their signature. Furthermore, since it is static, it is external to the constructor, and doesn't have the problems in your question.
You can use it as follows:
int main() {
auto f0 = foo::create();
auto f1 = foo::create(2);
// Next line doesn't compile if uncommented
// foo f2;
}
Note that it's impossible to create an object without this method, and the interface doesn't even contain init.
Assume we have next code:
class ISampleInterface
{
public:
virtual ~ISampleInterface() {} ;
virtual void Method1() = 0;
virtual void Method2() = 0;
};
class SampleClass : public ISampleInterface
{
public:
SampleClass() { };
~SampleClass() override { };
void Method1() { };
void Method2() { };
};
int main()
{
ISampleInterface *pObject = (ISampleInterface*)new SampleClass();
delete pObject;
return 0;
}
Is it better explicitly declare ~SampleClass() as override or don't care?
P.S. Please, focus on override and don't care the implementation of destructor itself. It could be defined, I just put example here in order to make my question clear.
I wouldn't do that. I also don't see any point in declaring explicitly a trivial destructor. Let the compiler do its job. You might need to introduce a virtual destructor into your class to (i) make the class polymorphic - although any function will do for that - and (ii) to assist in memory management, but that's not strictly relevant here.
Or, if you must do such a thing, consider using = default notation rather than supplying the empty body explicitly.
IMHO opinion any answer would be biased (i.e., opinion based). Generally, using the override specifier amongst many advantages has the advantage of eliminating:
inadvertent overriding : Inadvertently override a virtual function by declaring a member function that accidentally has the same name and signature as a base class’s virtual member function.
signature mismatches: Define a function in derived class that intended to override a virtual function in the base class but the two functions have different signatures.
There are even people that back up the opinion that the use of override specifier should be mandatory in future version of C++.
Now, in the particular case of a destructor, attaching the override specifier seems to me a little verbose.
And I'll try to clear my stand. A destructor is a special member function. Considering a class hierarchy, a derived class's destructor overrides by default the destructor of the base class (that for the known reasons should be declared virtual). Furthermore, you don't have the advantages mentioned earlier (i.e., there can't be either inadvertent overriding nor signature mismatch in a case of a destructor).
Thus, I wouldn't specify a destructor override.
Looks like I found at least one reason why it is better to make destructor override.
override for destructors prevents to make mistake when destructor of interface base class is not declared as virtual.
Let's say I have a class FooContainer that aggregates unique_ptr objects of type Foo
#include <vector>
#include <memory>
class FooContainer
{
protected:
std::vector<std::unique_ptr<Foo>> many;
//other attributes
public:
FooCoontainer(const FooContainer&);
//handling functions for Foo
};
The question is how to correctly implement deep copy constructor, and what is syntax for it. Simply assigning
FooContainer::FooContainer(const FooContainer& fc)
{
many=fc.many;
}
will attempt to copy the pointers and will be (thankfully) disallowed by the compiler for unique_ptr. so I would need to do something like this
FooContainer::FooContainer(const FooContainer& fc)
{
many.reserve(fc.many.size());
for(int i=0;i<fc.many.size();i++)
many.emplace_back(new Foo(*fc.many[i]));//assume that Foo has a copy constructor
}
Is this the way to do it? Or may be I should use shared_ptr instead of unique_ptr?
I also have an additional question.
The reason to go for smart pointers (and also for protected in the code above) is that I have derived class BarContainer that aggregates objects Bar in many, which are in turn subclass of Foo. Since the the handling of Bar is very similar to Foo this approach will allow to save a lot of duplicate code compared to two separate classes.
However,. the copy constructor of the BarContainer is problematic. It will the call copy constructor of FooContainer, that will go agead and copy only the Foo part instead of whole Bar. even worse, any invocation of the virtual methods of Bar will call the version of Foo.
So I need a way to override this behaviour.Making the copy constructor virtual is not possible.
Also the copy constructor of Bar could discard the result of Foo copy constructor and to dperform correct copying, but this is quite inefficient
So what is the best solution for this problem?
Or may be I should use shared_ptr instead of unique_ptr?
That depends on whether you require deep copies or are okay with shallow copies (meaning changes to one will also be visible in the other).
However,. the copy constructor of the BarContainer is problematic. It will the call copy constructor of FooContainer, that will go agead and copy only the Foo part instead of whole Bar.
The usual fix is to give your base class a virtual method clone:
class Foo {
public:
Foo(Foo&&) = default;
Foo& operator=(Foo&&) = default;
virtual ~Foo() = 0;
virtual std::unique_ptr<Foo> clone() const = 0;
protected: // or public if appropriate
Foo(const Foo&);
Foo& operator=(const Foo&);
};
class Bar : public Foo {
public:
virtual std::unique_ptr<Foo> clone() const;
};
std::unique_ptr<Foo> Bar::clone() const {
return make_unique<Bar>(*this);
}
If Foo is not abstract, it would also have an actual implementation of clone().
FooContainer::FooContainer(const FooContainer& fc)
{
many.reserve(fc.many.size());
for (auto const& fptr : fc.many)
many.emplace_back(fptr->clone());
}
I've used a template function make_unique, which was accidentally forgotten from the C++11 Standard, but will be official soon. If your compiler doesn't have one, it's simple to put your own in some header file:
template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&& ... args) {
return std::unique_ptr<T>( new T(std::forward<Args>(args)...) );
}
(Together, unique_ptr, make_unique, shared_ptr, make_shared, and vector finish the huge language improvement meaning you'll almost never need the low-level and dangerous new or delete keywords again.)
I am writing an GL effect system in my application so i have a superclass called
cEffect - which handles loading/parsing configuration file for each effect
and other inherited classess
cFX<name> - for every effect i add ( blur, bloom, chaos,... ).
The code is simplified here but looks like this:
Class cEffect
{
public:
bool ParseString(...);
private:
int m_nStartFrame;
int m_nEndFrame;
float m_fSpeed;
};
// Blur effect
Class cFXBlur : public cEffect
{
public:
bool RenderFrame(...);
};
// Bloom effect
Class cFXBloom : public cEffect
{
public:
bool RenderFrame(...);
};
// Scene drawing effect
Class cFXScene : public cEffect
{
public:
bool RenderFrame(...);
};
// Clear the depth/color buffer
Class cFXClearBuffers : public cEffect
{
public
bool RenderFrame(...);
}
Now, the demo engine handles a
std::vector<cEffect *> m_pvEffects;
Vector that has a list of effects added.
And when an effect is added to the current time (let's say i add a blur)
i add it like:
// Blur to be added
cEffect *newEffect = new cFXBlur;
newEffect->SetStartTime(x);
newEffect->SetEndTime(y);
newEffect->SetPower(13.0f);
newEffect->SetTexture(...);
// Now add the effect to the effects list.
m_pvEffects.push_back(newEffect);
Now, when i render i iterate through m_pvEffects list - but also i would like to call
an RenderFrame method ( which is public in every CFX<name> effect).
(*it)->RenderFrame(...)
But compiler says:
error C2039: 'RenderFrame' : is not a member of 'CEffect'
I kinda understand why it happens but can't really think of a way how can i fix this,
can you guys help me out please - it seems like i lost the plot ...
Thanks for any suggestion, what can i do to add CFX to a cEffect vector and later
use -> RenderFrame method?
You should change your class cEffect to:
Class cEffect
{
public:
bool ParseString(...);
virtual bool RenderFrame(...) = 0;
private:
int m_nStartFrame;
int m_nEndFrame;
float m_fSpeed;
};
You need the keyword virtual, if you want to redefine a method in a subclass. The = 0 makes the class cEffect abstract (i.e. you cannot create an object directly of the type cEffect), therefore subclasses must implement the method RenderFrame(...)
The error occurs, because cEffect has no member function called RenderFrame. What you want is a virtual function, a fundamental concept of object oriented programming. Basically you need to add a function
virtual bool RenderFrame(...);
to your cEffect definition. The virtual keyword basically tells the compiler to resolve it at runtime. This means if you call this method on a cEffect pointer or a reference, the corresponding method of the concrete derived class this pointer or reference point to is called. In this case you should also declare the method as virtual in all derived classes (although this is not neccessary, it makes your code clearer).
If you do not want the base class method to do anything and you want to require all derived classes to override it with their own implementation, then you can make this method pure virtual in the base class, by decralring it like
virtual bool RenderFrame(...) = 0;
This basically tells the compiler, that this is an abstract method, which doesn't have a concrete implementation and is only implemented by derived classes.
This is a very simplified explanation (appologies to every expert who thinks my wordings not 100% exact). You should read some more material on object oriented programming, especially in conjunction with C++.