1
\$\begingroup\$

I am creating a small library for controlling bars of leds and have some doubts about my design.

I have 2 basic entities in the design so far:

BarService (and implementation)

template<class T>

class BarService{
public:
  virtual void turnOnLeds(T* bar, int end) = 0;
class PinBarService : public BarService<PinBar>{
public:
  virtual void turnOnLeds(PinBar* bar, int end);
  void initPins(PinBar* bar);
};
class OpampService : public BarService<OpampBar>{
public:
  virtual void turnOnLeds(OpampBar* bar, int end);
  void initPins(OpampBar* bar);
};

Bar models:

class Bar{
private:
  int ledCount;
public:
  Bar(int ledCount);
  int getLedCount();
};
class BasicBar : public Bar{
private:
  int* pins;
public:
  BasicBar(int ledCount, int pins[]);
  int getPin(int index);
};
class OpampBar : public Bar{
private:
  int input;
public:
  OpampBar(int ledCount, int input);
};

My reasoning for separating these is that I feel the Bar models should only contain information about themselves, thus allowing me to create more classes later on which use that information rather than having the bar itself perform actions (like writing to hardware).

The reason I'm having doubts is that by using templates every implementation of the service needs to accept a different model.

My question comes down to: Am I going overboard with separating the model from its actions? and are templates a good solution here? and overall, what could be improved about this design?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Generally "template vs polymorphism" is a complex topic. A simple rule of thumb: if it is high level (e.g., service you instantiate a few times) go virtual, if it is low level (you need to create a array of million these objects) then go template.

In your case... honestly your interface makes little sense to me - it is difficult to make any advices.

Say, is there any point in Bar class? It simply holds an int and serves no other purpose. Just having a common function and variable doesn't imply that you need to have a shared basic class. If it had virtual destructor then I could understand to a certain degree.

Why OpampBar is a class? It just holds two integers. Why not make it a struct with public members? Why make it unnecessarily complicated?

What is this BasicBar and what is this pins raw pointer? Is it a pointer to an array? A pointer to data that doesn't belong to it? Why not use std::vector<int>? There are lots of well made classes and functions in STL, why not utilize them?

What is the point of BarService? It is an interface class. I know of two purposes of interface classes: (1) To allow your program to switch between different derived classes easily. (2) Hide implementation. Is this the case? (Well, it can also serve as poor man's concept substitude... but I doubt that you use any SFINAE).

You need to watch and read tutorials on C++. There are plenty for free - just google it. There are lots of CppCon videos on YouTube where they explain additions to C++ (you gotta learn what was added in C++11/14 as well as what STL already had for 20 years).

\$\endgroup\$
14
  • \$\begingroup\$ In an embedded system it Is often prefered or even the only viable way to avoid dynamic memory allocation. Maybe thats why array Is used instead of std::vector... \$\endgroup\$
    – slepic
    Dec 9, 2019 at 7:30
  • \$\begingroup\$ @slepic if you want to limit dynamic allocation then one can use std::unique_ptr<int[]> and utilize move operations. \$\endgroup\$
    – ALX23z
    Dec 9, 2019 at 7:58
  • \$\begingroup\$ But wouldn't that still do dynamic memory allocation? unique_ptr just handles the deallocation for you once the unique_ptr is destroyed. Isnt't it true, that it can't help if you wanted to avoid dynamic memory allocation entirely, not just limit it? \$\endgroup\$
    – slepic
    Dec 11, 2019 at 6:55
  • \$\begingroup\$ @slepic it would be in a more controlled fashion - so you can pass buffers around. Or you want a system where there is no dynamic allocation at all? I mean, in this case I doubt you can use anything beyond C. \$\endgroup\$
    – ALX23z
    Dec 11, 2019 at 12:14
  • \$\begingroup\$ Not true. You can still use classes, parameter overloading, all the fancy stuff. Dynamic does not mean OOP. Dynamic just means you decide (the amount/type of objects to create - the amount of memory to allocate) at runtime. But you can still put all that stuff on the stack as long as you know the number and types of objects you create at compile time. And OP never stated anything that implies he need to allocate variable amount of objects, nor create any objects of polymorphic type which he could not determine at compile time. \$\endgroup\$
    – slepic
    Dec 11, 2019 at 21:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.