I have a generic question on C++ class design. For example I have a need for a packet generator. So given a type of packet I have to generate the packet of that type. So I have a base packet generator class.
Approach 1:
class BasePacketGenerator {
public:
virtual Packet* generatePacket (int type); // implements the generic case
// hence not pure virtual
protected:
//
// Common functionality for all types
//
virtual void massagePacket (Packet& pkt); // called by generatePacket
// but needs special handling for
// some types
virtual void calculateCheckSum(Packet& pkt); // called by generate packet
...
};
Derived classes to handle each type:
class Type1PacketGenerator : public BasePacketGenerator {
public:
// Dont have to override any base class implementationa
protected:
void calculateCheckSum(Packet& pkt) override;
};
class Type2PacketGenerator : public BasePacketGenerator {
public:
Packet* generatePacket(int type) override;
};
Here for Type1 generator, we are using polymorphism. But the base-class calls, the derived class functionality polymorphically. I wonder if this is a good Idiom? Or there should be a intermediator class
Approach 2:
class TypeHandler {
virtual Packet* setupPacket();
virtual void calculateCheckSum(Packet& pkt);
virtual void setupFields (Packet& pkt);
}
class PacketGenerator {
public:
TypeHandler *handler_; // lets say this is setup based on the type
Packet* generatorPacket(int type)
{
auto packet = handler_->setupPacket();
handler_->massagePacket();
handler_->calculateCheckSum(*packet);
return packet;
}
}
Is there any advantage with going with one approach or the other?
Approach1 is more flexible as it doesn't have to follow the same way of doing things. Eg: if Type2Generator doesn't need a checksum, it doesn't even have to call the calculateCheckSum() or if it needs some additional functionality, we don't have to add it to all Type generators.
But Approach 2 is more readable as all types do the things same way.
Modern design sensibilities tend to favor a very aggressive separation of concerns. As such, this leads to preferring base classes that are nothing but pure virtual function declarations.
Each class is responsible for 1 thing.
As such, your second approach is considered much preferable. The main reason (and the only one you really need) being: it makes it much easier to write proper unit tests.
Edit: mind you, it still looks a bit clunky, but this is more a matter for The codereview stackexchange, where you could get detailed feedback on your structure.
Related
I have a code like this using CRTP and C++20:
template<class Derived>
class Base {
public:
void m() {
static_cast<Derived*>(this)->feature();
}
virtual constexpr void feature() = 0;
}
class BaseImpl: public Base<BaseImpl> {
virtual constexpr void feature() final override { // ... };
}
Is there a way to remove vptr so the object won't take 8 bytes (for x64), and instead will take only 1 byte? (since it never uses runtime polymorphism)?
In real code, the hierarchy is much more complex and it has 2 vptr (so it takes 16 bytes). Are there any extensions like for GCC or MSVC?
Yeah, definitely, one of the solutions is just to remove the virtual method. But since it has a complex hierarchy, it brings extremely ugly errors and unmaintainable code, since programmers should guess what methods must be implemented via reading unreadable template instantiation errors.
The whole goal is to achieve a Java-like hierarchy (with interfaces, override checks, etc), but with zero-cost abstraction.
I did some experiments (exploring code disassembly) and the compiler completely optimized all the virtual calls, providing zero-cost abstraction. EXCEPT it extends the object to have a vptr which is never used in my code.
I found something like __declspec(novtable) but vptr still takes space.
And yes, the size of the objects is extremely important to be as small as possible.
You're using CRTP, which uses static dispatch. There's absolutely no reason to use virtual here. If you want to ensure that the method exists with the right signature, use a static_assert.
template<class Derived>
class Base {
public:
void m() {
static_cast<Derived*>(this)->feature();
}
~Base() {
static_assert(std::is_same_v<void,decltype(static_cast<Derived*>(this)->feature())>);
}
};
class BaseImpl: public Base<BaseImpl> {
public:
constexpr void feature() { };
};
I have an idea to architecting classical entity-component in a better way with variadic template inheritance. This question stems from funky experiments in the context of 3d-graphics but i believe i have it broken down to a very abstract question about C++. I am able to use C++20 in the scope in which it is currently implemented in Microsoft cl aka. the MSVC++19-Toolchain.
So. A few Base classes:
class basic {
public:
std::wstring get_name() { return name; }
virtual void do_something_idk_virtual() = 0;
virtual ~basic() {}
private:
std::wstring name;
}
class has_legs {
public:
virtual void walk() = 0;
virtual ~has_legs() {}
}
class has_wings {
public:
virtual void fly() = 0;
virtual ~has_wings() {}
}
template<typename... Ts>
class entity : public basic, public Ts... {
public:
virtual ~entity() {}
}
So far, so good. Now i want to make a duck:
class duck : entity<has_wings, has_legs> {
public:
virtual ~duck() {}
virtual void walk() { cout << "walk" << endl; }
virtual void fly() { cout << "fly" << endl; }
virtual void do_something_idk_virtual() { } // nothing,
}
still, seems to work. The problem is: I know have data structure (say a linked_list, or some sort of graph) and I use the visitor-pattern to work with basic*-typed things. I now have a lot of Code that looks like this. This is, quite literally, the central and critical part of a my program:
void visit(basic* node) {
//here i find out, through magic or some other kind of out-of-scope-mechanism that node is at least a has_wings. Problem:
reinterpret_cast<has_wings*>(node)->fly(); //does not work, will call basic::do_something_idk_virtual(). As far as i understand, this is because the compiler-generated vtable does not change via the reinterpret_cast.
reinterpret_cast<entity<has_wings>*>(node)->fly(); //might, work, problems start to come in if node is of some type that has_wings and has_legs. It sometimes calls some other method, depending on the ordering in declaring the class.
}
Solution
Have every component (aka. the pure interfaces) and the entity-class virtually inherit from basic
in basic add the non-virtual method:
template<typename TComponent> TComponent* get_component() {
return dynamic_cast<TComponent*>(this);
}
This will then fix vtables. I am not sure why dynamic_cast does that.
First of all, your template gives you nothing. class duck : public basic, public has_wings, public has_legs is absolutely identical.
Second, you need to decide what your level of polymorphic access is. If your level is basic, than it has to have already defined all the virtuals you want to be accessing (i.e. has_wings, fly) An interface where you need dynamic_casts to arrive to correct dynamic type (your example with reinterpret_cast is just wrong, you can't use reinterpret_cast to move through class hierarchy) is a poorly written interface.
Sometimes visitor pattern can be employed, but in my mind, it tends to produce extremely hard to troubleshoot code.
You have to use static_cast or dynamic_cast to move within an inheritance hierarchy, and static_cast can’t descend virtual inheritance or cross-cast (in one step) because the layout of different classes that derive from the source and destination types may differ. As it is, you’d have to know the actual type (not just that it had a given aspect) to do the conversion. If you have your “aspect” classes inherit from basic—virtually, so that there is a unique basic* to be had—you can then use dynamic_cast not for its checking purpose but so as to find the appropriate vtable for the aspect in question.
If you can’t afford that, you may want to amalgamate the interfaces somehow. You then have to be careful to call the functions only when they’re meaningful; that’s already the case (“through magic”), but then the ordinary call syntax might be an attractive nuisance. You might also try some C-style polymorphism with a manually-created vtable with function pointers for each optional behavior.
In below code I have abstract class TestAlgModule which I will be exposing to library users and there are several functionalities they can use such as VOLUME, MIXER and so on. However, suppose users need a new function which is added only in MixerManager then I need to add that in TestAlgModule abstract class and now suddenly all the derived class needs to add that without any benefit.
How do I avoid this?
#include <iostream>
using namespace std;
enum {VOLUME, MIXER, UNKNONWN};
class TestAlgModule {
public:
virtual void open(int type) = 0;
virtual void close(int type) = 0;
};
class volumeManager : public TestAlgModule
{
public:
void open(int type) {}
void close(int type) {}
};
class mixerManager : public TestAlgModule
{
public:
void open(int type) {}
void close(int type) {}
void differentFunction() {};
};
/* users calls this to get algModule and then call functions to get the job done */
TestAlgModule *getTestAlgModule(int type) {
switch(type) {
case VOLUME:
return new volumeManager();
case MIXER:
return new mixerManager();
default:
break;
}
return nullptr;
}
int main() {
TestAlgModule * test = getTestAlgModule(MIXER);
test->open();
//test->differentFunction(); this can't be called as it is not part of abstract class and users are exposed only abstract class
return 0;
}
If something is not clear please let me know and I will do my best to answer it. I am looking for a better way to do this i.e. change in VolumeManager should be independent of MixerManager.
If you want to use an abstract factory, like you did in above code, then you need to return a pointer to the base class. That is correct. And then you need to invoke all functions through the base pointer.
By the way, please do not use raw pointers. Please use std::unique pointers instead.
There are 2 possible solutions.
Add the interface functions as a none pure, but still virtual function to your base class, with a default behaviour.
virtual void differentFunction() {}
Because of the other pure functions, the base class is still abstract. This may lead to a fat interface. But in many cases it is an acceptable solution.
The second possibility is to downcast the base class pointer to your needed pointer, using dynamic_cast and checking the return value of the dynamic cast.
if(mixerManager* mm = dynamic_cast<mixerManager*>(test)) {
mm->differentFunction();
}
All this depends of course on the overall design and what you want to achieve. But the above 2 are the standard patterns.
There are also other design patterns that may fit your needs, like builder or prototype. Please check.
I am trying to complete some school homework, and I've just noticed there might be a problem caused by reusing a function from a base class in a multiply inherited derived class.
Let's say I have these classes:
class A
class B: public A
class C: public A
class D: public B, public C
Each class has this method:
virtual void read(ifstream& in);
In class B and in class C, the read() function is also calling class A::read():
void B::read(ifstream& in)
{
A::read(in);
/* read method of B*/
}
void C::read(ifstream& in)
{
A::read(in);
/* read method of C*/
}
Now, the problem is, that when I want to make a read() function for class D, I'm actually calling A::read() twice:
void D::read(ifstream& in)
{
B::read(in);
C::read(in);
/* read method of D*/
}
I know I can use the option of using the A::read() only in one class (B or C), but let's say I need to use it in both classes.
This is an example of why multiple inheritance, especially from a common ancestor, is discouraged. Not because it's always bad - though it often is!- but more because it's usually difficult. If you can find an alternative, that's often preferable. Not necessarily. I'm sure you'll ponder this and decide if it's the best design. But for now, we're here to look at ways to avoid repeating A::read() and other pitfalls.
I start with an analogy to the famous Dreaded Diamond of Doom - not anywhere near as dread-worthy as legend suggests, but worth bearing in mind. It's illustrative that when working around the 'duplicated base members' problem created by such a diamond-shape inheritance hierarchy, by using virtual inheritance - the derived class now becomes fully responsible for calling all constructors of all of its virtual bases. Constructor calls don't chain upwards like normal, and data member initialisation is weird. Google it!
N.B. You should use virtual inheritance if the top class of your diamond-shaped hierarchy has any data members, to avoid duplicating/introducing ambiguity for them, too. That's what it's for. But back to the main topic where I use it as an analogy to functions (which don't strictly require it).
The idea is to take inspiration from virtual inheritance's requirement for the final class to manually call virtual bases' constructors, by handling derived classes' read() behaviours the same way: Avoid repeated calls by making each of your derived classes' public-facing read() methods fully responsible for calling all base ones. This also gives you fine control over not only which of the bases' methods are called - but also of their order.
How? We can factor out the real work of each derived read() to protected 'implementation' functions in each class, and provide public overridden 'wrapper functions' in each final class. The wrapper functions will then be responsible for calling their respective class's impl and that of any required bases, in whichever order you want:
class A {
protected:
void read_impl(ifstream &in) { /* A-specific stuff */ }
public:
virtual void read(ifstream &in)
{
read_impl(in);
}
};
class B: public A { // N.B. virtual public if A has data members!
protected:
void read_impl(ifstream &in) { /* B-specific stuff */ }
public:
virtual void read(ifstream &in)
{
A::read_impl(in);
read_impl(in); // B
}
};
class C: public A {
protected:
void read_impl(ifstream &in) { /* C-specific stuff */ }
public:
virtual void read(ifstream &in)
{
A::read_impl(in);
read_impl(in); // CMy
}
};
class D: public B, public C {
protected:
void read_impl(ifstream &in) { /* D-specific stuff */ }
public:
virtual void read(ifstream &in)
{
A::read_impl(in);
B::read_impl(in); // avoids calling A again from B
C::read_impl(in); // ditto from C
read_impl(in); // D
}
};
With this, you gain complete control over what base stuff each final class dones, and when, without unwanted repeated calls. In terms of DRY, impl functions mean no repetition of behavioural code is done for intermediate classes: the writing in each derived read() is all useful declarative information about how they orchestrate bases' behaviours. You can also add extra stuff between, etc.
A very non-generic way to fix this issue is with booleans, just a switch for each class (B && C) to state if I should call my super class's function.
Another way to fix it is just not to call A's function in B or C.
It seems to be the prevailing opinion that using protected data members is a bad idea. I'm wondering what a good alternative would be in a specific case.
Take the following class called CModule, which represents a audio module (Amiga-style tracker music). Many different module formats exist but the only difference between them is in file format (Loading) and audio effects handling. CModule holds all the common functionality, the derived classes implement loading and effects for each specific format.
class CModule
{
public:
CModule(string Filename); //Song file name to load.
//Common methods...
void Play();
void Stop(); //Etc...
protected:
//Derived class should implement these with format specific code.
//Base class code calls these when needed.
virtual void Load()=0;
virtual void Effects()=0;
//Song information/data.
vector<CInstrument> Instruments;
vector<CPattern> Patterns;
//And much, MUCH more...
};
Almost all the data members are protected since the derived class's Load() function needs to fill them all. This is considered bad since it can break encapsulation if someone derives a class from the derived class. What would be the proper way to solve this problem? I've already found that using getters/setters is considered bad too.
Many thanks to anyone taking the time to read this :)
There's nothing wrong with using protected data members if using private won't work for your solution, using public data members however is almost never a good idea (however it can be sometimes too).
I would probably make your vectors private in this case but simply create getter and setter methods. Something along the lines of:
class CModule
{
public:
CModule(string Filename); //Song file name to load.
//Common methods...
void Play();
void Stop(); //Etc...
protected:
//Derived class should implement these with format specific code.
//Base class code calls these when needed.
virtual void Load()=0;
virtual void Effects()=0;
void AddInstrument(CInstrument instrument)
{
Instruments.push_back(instrument);
}
Instrument GetInstrument(int index)
{
return Instruments[index];
}
int InstrumentCount()
{
return Instruments.size();
}
private:
//Song information/data.
vector<CInstrument> Instruments;
vector<CPattern> Patterns;
//And much, MUCH more...
};
This is a start just for instruments, you'll also have to take a similar approach with patterns. Alternatively you could also just pass back the vector but this is a little more encapsulated.
Also note that I am doing this off the top of my head and haven't tested it against typos of whatever but hopefully it conveys the idea.