How do I remove this inheritance-related code smell?How do you set, clear, and toggle a single bit?Prefer composition over inheritance?How do I iterate over the words of a string?How can I profile C++ code running on Linux?Difference between private, public, and protected inheritancePython class inherits objectC++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?What are the nuances of scope prototypal / prototypical inheritance in AngularJS?Why not inherit from List<T>?Downcasting best-practice (C++)

Has a life raft ever been successfully deployed on a modern commercial flight?

Cut the gold chain

Non-misogynistic way to say “asshole”?

Justifying Affordable Bespoke Spaceships

"Correct me if I'm wrong"

How to work with PETG? Settings, caveats, etc

Why is it easier to balance a non-moving bike standing up than sitting down?

How does DC work with natural 20?

Too early in the morning to have SODA?

Warnings using NDSolve on wave PDE. "Using maximum number of grid points" , "Warning: scaled local spatial error estimate"

What is "industrial ethernet"?

Subtract the Folded Matrix

Mathematically modelling RC circuit with a linear input

I just entered the USA without passport control at Atlanta airport

I found a password with hashcat, but it doesn't work

Can you use one creature for both convoke and delve for Hogaak?

Methodology: Writing unit tests for another developer

In the US, can a former president run again?

What is the highest voltage from the power supply a Raspberry Pi 3 B can handle without getting damaged?

Am I legally required to provide a (GPL licensed) source code even after a project is abandoned?

Designing a magic-compatible polearm

Umlaut character order when sorting

Rejecting an offer after accepting it just 10 days from date of joining

How long did the SR-71 take to get to cruising altitude?



How do I remove this inheritance-related code smell?


How do you set, clear, and toggle a single bit?Prefer composition over inheritance?How do I iterate over the words of a string?How can I profile C++ code running on Linux?Difference between private, public, and protected inheritancePython class inherits objectC++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?What are the nuances of scope prototypal / prototypical inheritance in AngularJS?Why not inherit from List<T>?Downcasting best-practice (C++)






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








15















I need to implement a lot of derived classes with different const member data. The data processing should be handled in the base class, but I can't find an elegant way to access the derived data. The code below is working, but I really don't like it.



The code needs to run in a small embedded environment so extensive usage of heap or fancy libraries like Boost are no option.



class Base

public:
struct SomeInfo

const char *name;
const f32_t value;
;

void iterateInfo()

// I would love to just write
// for(const auto& info : c_myInfo) ...

u8_t len = 0;
const auto *returnedInfo = getDerivedInfo(len);
for (int i = 0; i < len; i++)

DPRINTF("Name: %s - Value: %f n", returnedInfo[i].name, returnedInfo[i].value);


virtual const SomeInfo* getDerivedInfo(u8_t &length) = 0;
;

class DerivedA : public Base

public:
const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;

virtual const SomeInfo* getDerivedInfo(u8_t &length) override

// Duplicated code in every derived implementation....
length = sizeof(c_myInfo) / sizeof(c_myInfo[0]);
return c_myInfo;

;

class DerivedB : public Base

public:
const SomeInfo c_myInfo[3] "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f ;

virtual const SomeInfo *getDerivedInfo(u8_t &length) override

// Duplicated code in every derived implementation....
length = sizeof(c_myInfo) / sizeof(c_myInfo[0]);
return c_myInfo;

;

DerivedA instanceA;
DerivedB instanceB;
instanceA.iterateInfo();
instanceB.iterateInfo();









share|improve this question









New contributor



SirNobbyNobbs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.



















  • Is Base supposed to be able to be instantiable directly, or only the derived types?

    – Nikos C.
    15 hours ago












  • No, I only instanciate the derived classes.

    – SirNobbyNobbs
    15 hours ago











  • @NikosC.Base is abstract, can't create instances of it.

    – Tanveer Badar
    15 hours ago






  • 1





    If SomeInfo c_myInfo[3] is const and has a compile-time constant initializer, why do you have it inside the object instead of static? Do you only create one instance of each type, so there isn't actually duplication of the pointers + floats? (Also a string key/value array doesn't sound great for efficiency if you're using it as a dictionary, but that's a separate issue. Sounds like a job for enum..)

    – Peter Cordes
    3 hours ago











  • I'd give you +1 for using the word "smell" and another for your nom de guerre (which relates extensively to the word "smell"), but Stack Exchange says I'm supposed to act more responsibly than that. Oh, what the heck. +1.

    – JBH
    2 hours ago

















15















I need to implement a lot of derived classes with different const member data. The data processing should be handled in the base class, but I can't find an elegant way to access the derived data. The code below is working, but I really don't like it.



The code needs to run in a small embedded environment so extensive usage of heap or fancy libraries like Boost are no option.



class Base

public:
struct SomeInfo

const char *name;
const f32_t value;
;

void iterateInfo()

// I would love to just write
// for(const auto& info : c_myInfo) ...

u8_t len = 0;
const auto *returnedInfo = getDerivedInfo(len);
for (int i = 0; i < len; i++)

DPRINTF("Name: %s - Value: %f n", returnedInfo[i].name, returnedInfo[i].value);


virtual const SomeInfo* getDerivedInfo(u8_t &length) = 0;
;

class DerivedA : public Base

public:
const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;

virtual const SomeInfo* getDerivedInfo(u8_t &length) override

// Duplicated code in every derived implementation....
length = sizeof(c_myInfo) / sizeof(c_myInfo[0]);
return c_myInfo;

;

class DerivedB : public Base

public:
const SomeInfo c_myInfo[3] "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f ;

virtual const SomeInfo *getDerivedInfo(u8_t &length) override

// Duplicated code in every derived implementation....
length = sizeof(c_myInfo) / sizeof(c_myInfo[0]);
return c_myInfo;

;

DerivedA instanceA;
DerivedB instanceB;
instanceA.iterateInfo();
instanceB.iterateInfo();









share|improve this question









New contributor



SirNobbyNobbs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.



















  • Is Base supposed to be able to be instantiable directly, or only the derived types?

    – Nikos C.
    15 hours ago












  • No, I only instanciate the derived classes.

    – SirNobbyNobbs
    15 hours ago











  • @NikosC.Base is abstract, can't create instances of it.

    – Tanveer Badar
    15 hours ago






  • 1





    If SomeInfo c_myInfo[3] is const and has a compile-time constant initializer, why do you have it inside the object instead of static? Do you only create one instance of each type, so there isn't actually duplication of the pointers + floats? (Also a string key/value array doesn't sound great for efficiency if you're using it as a dictionary, but that's a separate issue. Sounds like a job for enum..)

    – Peter Cordes
    3 hours ago











  • I'd give you +1 for using the word "smell" and another for your nom de guerre (which relates extensively to the word "smell"), but Stack Exchange says I'm supposed to act more responsibly than that. Oh, what the heck. +1.

    – JBH
    2 hours ago













15












15








15


3






I need to implement a lot of derived classes with different const member data. The data processing should be handled in the base class, but I can't find an elegant way to access the derived data. The code below is working, but I really don't like it.



The code needs to run in a small embedded environment so extensive usage of heap or fancy libraries like Boost are no option.



class Base

public:
struct SomeInfo

const char *name;
const f32_t value;
;

void iterateInfo()

// I would love to just write
// for(const auto& info : c_myInfo) ...

u8_t len = 0;
const auto *returnedInfo = getDerivedInfo(len);
for (int i = 0; i < len; i++)

DPRINTF("Name: %s - Value: %f n", returnedInfo[i].name, returnedInfo[i].value);


virtual const SomeInfo* getDerivedInfo(u8_t &length) = 0;
;

class DerivedA : public Base

public:
const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;

virtual const SomeInfo* getDerivedInfo(u8_t &length) override

// Duplicated code in every derived implementation....
length = sizeof(c_myInfo) / sizeof(c_myInfo[0]);
return c_myInfo;

;

class DerivedB : public Base

public:
const SomeInfo c_myInfo[3] "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f ;

virtual const SomeInfo *getDerivedInfo(u8_t &length) override

// Duplicated code in every derived implementation....
length = sizeof(c_myInfo) / sizeof(c_myInfo[0]);
return c_myInfo;

;

DerivedA instanceA;
DerivedB instanceB;
instanceA.iterateInfo();
instanceB.iterateInfo();









share|improve this question









New contributor



SirNobbyNobbs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











I need to implement a lot of derived classes with different const member data. The data processing should be handled in the base class, but I can't find an elegant way to access the derived data. The code below is working, but I really don't like it.



The code needs to run in a small embedded environment so extensive usage of heap or fancy libraries like Boost are no option.



class Base

public:
struct SomeInfo

const char *name;
const f32_t value;
;

void iterateInfo()

// I would love to just write
// for(const auto& info : c_myInfo) ...

u8_t len = 0;
const auto *returnedInfo = getDerivedInfo(len);
for (int i = 0; i < len; i++)

DPRINTF("Name: %s - Value: %f n", returnedInfo[i].name, returnedInfo[i].value);


virtual const SomeInfo* getDerivedInfo(u8_t &length) = 0;
;

class DerivedA : public Base

public:
const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;

virtual const SomeInfo* getDerivedInfo(u8_t &length) override

// Duplicated code in every derived implementation....
length = sizeof(c_myInfo) / sizeof(c_myInfo[0]);
return c_myInfo;

;

class DerivedB : public Base

public:
const SomeInfo c_myInfo[3] "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f ;

virtual const SomeInfo *getDerivedInfo(u8_t &length) override

// Duplicated code in every derived implementation....
length = sizeof(c_myInfo) / sizeof(c_myInfo[0]);
return c_myInfo;

;

DerivedA instanceA;
DerivedB instanceB;
instanceA.iterateInfo();
instanceB.iterateInfo();






c++ c++11 inheritance






share|improve this question









New contributor



SirNobbyNobbs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.










share|improve this question









New contributor



SirNobbyNobbs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








share|improve this question




share|improve this question








edited 10 mins ago









Peter Mortensen

14.2k1988114




14.2k1988114






New contributor



SirNobbyNobbs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








asked 15 hours ago









SirNobbyNobbsSirNobbyNobbs

765




765




New contributor



SirNobbyNobbs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.




New contributor




SirNobbyNobbs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.














  • Is Base supposed to be able to be instantiable directly, or only the derived types?

    – Nikos C.
    15 hours ago












  • No, I only instanciate the derived classes.

    – SirNobbyNobbs
    15 hours ago











  • @NikosC.Base is abstract, can't create instances of it.

    – Tanveer Badar
    15 hours ago






  • 1





    If SomeInfo c_myInfo[3] is const and has a compile-time constant initializer, why do you have it inside the object instead of static? Do you only create one instance of each type, so there isn't actually duplication of the pointers + floats? (Also a string key/value array doesn't sound great for efficiency if you're using it as a dictionary, but that's a separate issue. Sounds like a job for enum..)

    – Peter Cordes
    3 hours ago











  • I'd give you +1 for using the word "smell" and another for your nom de guerre (which relates extensively to the word "smell"), but Stack Exchange says I'm supposed to act more responsibly than that. Oh, what the heck. +1.

    – JBH
    2 hours ago

















  • Is Base supposed to be able to be instantiable directly, or only the derived types?

    – Nikos C.
    15 hours ago












  • No, I only instanciate the derived classes.

    – SirNobbyNobbs
    15 hours ago











  • @NikosC.Base is abstract, can't create instances of it.

    – Tanveer Badar
    15 hours ago






  • 1





    If SomeInfo c_myInfo[3] is const and has a compile-time constant initializer, why do you have it inside the object instead of static? Do you only create one instance of each type, so there isn't actually duplication of the pointers + floats? (Also a string key/value array doesn't sound great for efficiency if you're using it as a dictionary, but that's a separate issue. Sounds like a job for enum..)

    – Peter Cordes
    3 hours ago











  • I'd give you +1 for using the word "smell" and another for your nom de guerre (which relates extensively to the word "smell"), but Stack Exchange says I'm supposed to act more responsibly than that. Oh, what the heck. +1.

    – JBH
    2 hours ago
















Is Base supposed to be able to be instantiable directly, or only the derived types?

– Nikos C.
15 hours ago






Is Base supposed to be able to be instantiable directly, or only the derived types?

– Nikos C.
15 hours ago














No, I only instanciate the derived classes.

– SirNobbyNobbs
15 hours ago





No, I only instanciate the derived classes.

– SirNobbyNobbs
15 hours ago













@NikosC.Base is abstract, can't create instances of it.

– Tanveer Badar
15 hours ago





@NikosC.Base is abstract, can't create instances of it.

– Tanveer Badar
15 hours ago




1




1





If SomeInfo c_myInfo[3] is const and has a compile-time constant initializer, why do you have it inside the object instead of static? Do you only create one instance of each type, so there isn't actually duplication of the pointers + floats? (Also a string key/value array doesn't sound great for efficiency if you're using it as a dictionary, but that's a separate issue. Sounds like a job for enum..)

– Peter Cordes
3 hours ago





If SomeInfo c_myInfo[3] is const and has a compile-time constant initializer, why do you have it inside the object instead of static? Do you only create one instance of each type, so there isn't actually duplication of the pointers + floats? (Also a string key/value array doesn't sound great for efficiency if you're using it as a dictionary, but that's a separate issue. Sounds like a job for enum..)

– Peter Cordes
3 hours ago













I'd give you +1 for using the word "smell" and another for your nom de guerre (which relates extensively to the word "smell"), but Stack Exchange says I'm supposed to act more responsibly than that. Oh, what the heck. +1.

– JBH
2 hours ago





I'd give you +1 for using the word "smell" and another for your nom de guerre (which relates extensively to the word "smell"), but Stack Exchange says I'm supposed to act more responsibly than that. Oh, what the heck. +1.

– JBH
2 hours ago












8 Answers
8






active

oldest

votes


















12














You don't need any virtuals or templates here. Just add a SomeInfo* pointer and its length to Base, and provide a protected constructor to initialize them (and since there's no default constructor, it won't be possible to forget to initialize them).



The constructor being protected is not a hard requirement, but since Base is not an abstract base class anymore, making the constructor protected prevents Base from being instantiated.



class Base

public:
struct SomeInfo

const char *name;
const f32_t value;
;

void iterateInfo()

for (int i = 0; i < c_info_len; ++i)
DPRINTF("Name: %s - Value: %f n", c_info[i].name,
c_info[i].value);



protected:
explicit Base(const SomeInfo* info, int len) noexcept
: c_info(info)
, c_info_len(len)


private:
const SomeInfo* c_info;
int c_info_len;
;

class DerivedA : public Base

public:
DerivedA() noexcept
: Base(c_myInfo, sizeof(c_myInfo) / sizeof(c_myInfo[0]))


private:
const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;
;

class DerivedB : public Base

public:
DerivedB() noexcept
: Base(c_myInfo, sizeof(c_myInfo) / sizeof(c_myInfo[0]))


private:
const SomeInfo c_myInfo[3]
"NameB1", 2.1f,
"NameB2", 2.2f,
"NameB2", 2.3f
;
;


You can of course use a small, zero-overhead wrapper/adapter class instead of the c_info and c_info_len members in order to provide nicer and safer access (like begin() and end() support), but that's outside the scope of this answer.






share|improve this answer




















  • 1





    This grows the size of every object by 1 pointer + 1 int. If you have many more instances of these objects than you do derived types, the OP's solution uses less total memory (data + code). They mention they're in a memory-constrained embedded environment. On a high-end system, the extra level of indirection is still a downside. (At least the pointer will typically be in the same cache line as the start of the data and the vtable pointer, so the extra latency is just 1 L1d cache ~load-use latency. Not an extra cache miss)

    – Peter Cordes
    3 hours ago



















4














You could make Base a template and take the length of your const array. Something like this:



template<std::size_t Length>
class Base

public:
struct SomeInfo

const char *name;
const float value;
;

const SomeInfo c_myInfo[Length];

void iterateInfo()

//I would love to just write
for(const auto& info : c_myInfo)
// work with info


;


And then initialize the array accordingly from each base class:



class DerivedA : public Base<2>

public:
DerivedA() : Base<2> SomeInfo"NameA1", 1.1f, "NameA2", 1.2f
;

class DerivedB : public Base<3>

public:
DerivedB() : Base<3> SomeInfo"NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f
;


And then use as you normally would. This method removes the polymorphism and uses no heap allocation (e.g. no std::vector), just as user SirNobbyNobbs requested.






share|improve this answer
































    2














    You can use CRTP:



    template<class Derived>
    class impl_getDerivedInfo
    :public Base


    virtual const SomeInfo *getDerivedInfo(u8_t &length) override

    //Duplicated code in every derived implementation....
    auto& self = static_cast<Derived&>(*this);
    length = sizeof(self.c_myInfo) / sizeof(self.c_myInfo[0]);
    return self.c_myInfo;

    ;


    class DerivedA : public impl_getDerivedInfo<DerivedA>

    public:
    const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;
    ;

    class DerivedB : public impl_getDerivedInfo<DerivedB>

    public:
    const SomeInfo c_myInfo[3] "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f ;

    ;





    share|improve this answer






























      2














      One way with C++17 would be to return a "view" object representing your content list. This can then be used in a C++11 for statement. You could write a base function that converts start+len into a view, so you don't need to add to the virtual method cruft.



      It is not that difficult to create a view object that is compatible with C++11 for statement. Alternatively, you could consider using the C++98 for_each templates that can take a begin and end iterator: Your start iterator is start; the end iterator is start+len.






      share|improve this answer
































        1














        Start with a vocabulary type.



        template<class T>
        struct span
        T* b = nullptr;
        T* e = nullptr;
        span( T* s, T* f ):b(s), e(f)
        span( T* s, size_t l ):span(s, s+l)
        template<size_t N>
        span( T(&arr)[N] ):span(arr, N)
        T* begin() const return b;
        T* end() const return e;
        size_t size() const return end()-begin();
        bool empty() const return size()==0;
        T& front() const return *begin();
        T& back() const return *(end()-1);
        ;
        // this is just here for the other array ctor:
        template<class T>
        struct span<T const>
        T const* b = nullptr;
        T const* e = nullptr;
        span( T const* s, T const* f ):b(s), e(f)
        span( T const* s, size_t l ):span(s, s+l)
        template<size_t N>
        span( T const(&arr)[N] ):span(arr, N)
        template<size_t N>
        span( T(&arr)[N] ):span(arr, N)
        T const* begin() const return b;
        T const* end() const return e;
        size_t size() const return end()-begin();
        bool empty() const return size()==0;
        T const& front() const return *begin();
        T const& back() const return *(end()-1);
        ;


        now we can talk about a span<char>.



        class Base

        public:
        void iterateInfo()

        for(const auto& info : c_mySpan)
        DPRINTF("Name: %s - Value: %f n", info.name, info.value);


        private:
        span<const char> c_mySpan;
        Base( span<const char> s ):c_mySpan(s)
        Base(Base const&)=delete; // probably unsafe
        ;


        now your derived looks like:



        class DerivedA : public Base

        public:
        const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;
        DerivedA() : Base(c_myInfo)
        ;


        This has overhead of 2 pointers per Base. A vtable uses 1 pointer, makes your type abstract, adds indirection, adds 1 global vtable per Derived type.



        Now, in theory, you could get the overhead of this down to the length of the array, and presume that the array data starts right after Base, but that is fragile, non-portable and only useful if desperate.



        While you may be rightly leery of templates in embedded code (as you should be of any kind of code generation; code generation means you can generate more than O(1) binary from O(1) code), the span vocabulary type is compact and should be inlined to nothing if your compiler settings are reasonably aggressive.






        share|improve this answer






























          1














          Okay then let's simplify all the unnecessary complications :)



          Your code really boils down to the following:



          SomeInfo.h



          struct SomeInfo

          const char *name;
          const f32_t value;
          ;

          void processData(const SomeInfo* c_myInfo, u8_t len);


          SomeInfo.cpp



          #include "SomeInfo.h"

          void processData(const SomeInfo* c_myInfo, u8_t len)

          for (u8_t i = 0; i < len; i++)

          DPRINTF("Name: %s - Value: %f n", c_myInfo[i].name, c_myInfo[i].value);




          data.h



          #include "SomeInfo.h"

          struct A

          const SomeInfo info[2] "NameA1", 1.1f, "NameA2", 1.2f ;
          static const u8_t len = 2;
          ;

          struct B

          const SomeInfo info[3] "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f ;
          static const u8_t len = 3;
          ;


          main.cpp



          #include "data.h"

          int
          main()

          A a;
          B b;
          processData(a.info, A::len);
          processData(b.info, B::len);






          share|improve this answer

























          • Given the provided example you are right.But this is just a simplification to highlight my problem. The base class is already several hundred lines of code and every derived class also has much more inside than just the const info.

            – SirNobbyNobbs
            14 hours ago






          • 3





            Well, I can imagine. All I can suggest is to use composition instead of inheritance along with simple functions. Coding can be a simple and pleasurable experience. We just complicate everything for some reason :)

            – Adam Zahran
            14 hours ago











          • @SirNobbyNobbs "The base class is already several hundred lines of code" - That is more of a code smell than anything that your simplified example might highlight,

            – Goyo
            4 hours ago







          • 1





            There's no point having a u8_t len = 3; member in each struct; the length of the info[] array member is already statically known as part of the derived type. @SirNobbyNobbs: What you could do is have a small inline wrapper in each of A and B that passes the right args to a common processData function. It can be virtual if you need it to be, but letting it inline into each call site when you have full type info is good. (final on the derived type functions allows that in more cases.)

            – Peter Cordes
            2 hours ago











          • @PeterCordes Well I thought of that. But in order to retrieve the size we would need a function. This function could either be templated or repeated. But since I'm going for simplicity and avoiding code generation here I decided a little extra u8_t in the struct will harm no one :)

            – Adam Zahran
            2 hours ago


















          1














          You can move your data into a two-dimensional array outside of the classes and have each class return an index which contains relevant data.



          struct SomeInfo

          const char *name;
          const f32_t value;
          ;

          const vector<vector<SomeInfo>> masterStore
          "NameA1", 1.1f, "NameA2", 1.2f,
          "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f
          ;

          class Base

          public:
          void iterateInfo()

          // I would love to just write
          // for(const auto& info : c_myInfo) ...

          u8_t len = 0;
          auto index(getIndex());
          for(const auto& data : masterStore[index])

          DPRINTF("Name: %s - Value: %f n", data.name, data.value);


          virtual int getIndex() = 0;
          ;

          class DerivedA : public Base

          public:

          int getIndex() override

          return 0;

          ;

          class DerivedB : public Base

          public:

          int getIndex() override

          return 1;

          ;

          DerivedA instanceA;
          DerivedB instanceB;
          instanceA.iterateInfo();
          instanceB.iterateInfo();





          share|improve this answer




















          • 2





            Why a const std::vector for compile-time-constant data with known fixed size? Seems like a job for a flat 1D std::array<SomeInfo> with each derived class knowing the right start index + offset. (GetIndex returns a std::pair<int,int>). Or a std::array<std::vector<SomeInfo>>. Or maybe implicit lengths by using a flat array of SomeInfo objects with nullptr terminators for the end of each sub-array, if you only ever want to iterate in order.

            – Peter Cordes
            3 hours ago


















          1














          Just make the virtual function return a reference to the data directly (you need to change to vector then - not possible with array or C style array types with different sizes):



          virtual const std::vector<SomeInfo>& getDerivedInfo() = 0;


          or if pointers are the only feasible option, as a pointer range (iterators/range adapter would be preferred though if possible - more on that):



          virtual std::pair<SomeInfo*, SomeInfo*> getDerivedInfo() = 0;


          To make this last method work with range-based for loop: one way is to make a small 'range view' type that has the functions begin()/end() - essential a pair with begin()/end()



          Example:



          template<class T>
          struct ptr_range
          std::pair<T*, T*> range_;
          auto begin()return range_.begin();
          auto end()return range_.end();
          ;


          Then construct it with:



          virtual const ptr_range<SomeInfo> getDerivedInfo() override

          return std::begin(c_myInfo), std::end(c_myInfo);



          It is easy to make it non-template if a template is not desired.






          share|improve this answer

























            Your Answer






            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "1"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader:
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            ,
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );






            SirNobbyNobbs is a new contributor. Be nice, and check out our Code of Conduct.









            draft saved

            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56627438%2fhow-do-i-remove-this-inheritance-related-code-smell%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown

























            8 Answers
            8






            active

            oldest

            votes








            8 Answers
            8






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            12














            You don't need any virtuals or templates here. Just add a SomeInfo* pointer and its length to Base, and provide a protected constructor to initialize them (and since there's no default constructor, it won't be possible to forget to initialize them).



            The constructor being protected is not a hard requirement, but since Base is not an abstract base class anymore, making the constructor protected prevents Base from being instantiated.



            class Base

            public:
            struct SomeInfo

            const char *name;
            const f32_t value;
            ;

            void iterateInfo()

            for (int i = 0; i < c_info_len; ++i)
            DPRINTF("Name: %s - Value: %f n", c_info[i].name,
            c_info[i].value);



            protected:
            explicit Base(const SomeInfo* info, int len) noexcept
            : c_info(info)
            , c_info_len(len)


            private:
            const SomeInfo* c_info;
            int c_info_len;
            ;

            class DerivedA : public Base

            public:
            DerivedA() noexcept
            : Base(c_myInfo, sizeof(c_myInfo) / sizeof(c_myInfo[0]))


            private:
            const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;
            ;

            class DerivedB : public Base

            public:
            DerivedB() noexcept
            : Base(c_myInfo, sizeof(c_myInfo) / sizeof(c_myInfo[0]))


            private:
            const SomeInfo c_myInfo[3]
            "NameB1", 2.1f,
            "NameB2", 2.2f,
            "NameB2", 2.3f
            ;
            ;


            You can of course use a small, zero-overhead wrapper/adapter class instead of the c_info and c_info_len members in order to provide nicer and safer access (like begin() and end() support), but that's outside the scope of this answer.






            share|improve this answer




















            • 1





              This grows the size of every object by 1 pointer + 1 int. If you have many more instances of these objects than you do derived types, the OP's solution uses less total memory (data + code). They mention they're in a memory-constrained embedded environment. On a high-end system, the extra level of indirection is still a downside. (At least the pointer will typically be in the same cache line as the start of the data and the vtable pointer, so the extra latency is just 1 L1d cache ~load-use latency. Not an extra cache miss)

              – Peter Cordes
              3 hours ago
















            12














            You don't need any virtuals or templates here. Just add a SomeInfo* pointer and its length to Base, and provide a protected constructor to initialize them (and since there's no default constructor, it won't be possible to forget to initialize them).



            The constructor being protected is not a hard requirement, but since Base is not an abstract base class anymore, making the constructor protected prevents Base from being instantiated.



            class Base

            public:
            struct SomeInfo

            const char *name;
            const f32_t value;
            ;

            void iterateInfo()

            for (int i = 0; i < c_info_len; ++i)
            DPRINTF("Name: %s - Value: %f n", c_info[i].name,
            c_info[i].value);



            protected:
            explicit Base(const SomeInfo* info, int len) noexcept
            : c_info(info)
            , c_info_len(len)


            private:
            const SomeInfo* c_info;
            int c_info_len;
            ;

            class DerivedA : public Base

            public:
            DerivedA() noexcept
            : Base(c_myInfo, sizeof(c_myInfo) / sizeof(c_myInfo[0]))


            private:
            const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;
            ;

            class DerivedB : public Base

            public:
            DerivedB() noexcept
            : Base(c_myInfo, sizeof(c_myInfo) / sizeof(c_myInfo[0]))


            private:
            const SomeInfo c_myInfo[3]
            "NameB1", 2.1f,
            "NameB2", 2.2f,
            "NameB2", 2.3f
            ;
            ;


            You can of course use a small, zero-overhead wrapper/adapter class instead of the c_info and c_info_len members in order to provide nicer and safer access (like begin() and end() support), but that's outside the scope of this answer.






            share|improve this answer




















            • 1





              This grows the size of every object by 1 pointer + 1 int. If you have many more instances of these objects than you do derived types, the OP's solution uses less total memory (data + code). They mention they're in a memory-constrained embedded environment. On a high-end system, the extra level of indirection is still a downside. (At least the pointer will typically be in the same cache line as the start of the data and the vtable pointer, so the extra latency is just 1 L1d cache ~load-use latency. Not an extra cache miss)

              – Peter Cordes
              3 hours ago














            12












            12








            12







            You don't need any virtuals or templates here. Just add a SomeInfo* pointer and its length to Base, and provide a protected constructor to initialize them (and since there's no default constructor, it won't be possible to forget to initialize them).



            The constructor being protected is not a hard requirement, but since Base is not an abstract base class anymore, making the constructor protected prevents Base from being instantiated.



            class Base

            public:
            struct SomeInfo

            const char *name;
            const f32_t value;
            ;

            void iterateInfo()

            for (int i = 0; i < c_info_len; ++i)
            DPRINTF("Name: %s - Value: %f n", c_info[i].name,
            c_info[i].value);



            protected:
            explicit Base(const SomeInfo* info, int len) noexcept
            : c_info(info)
            , c_info_len(len)


            private:
            const SomeInfo* c_info;
            int c_info_len;
            ;

            class DerivedA : public Base

            public:
            DerivedA() noexcept
            : Base(c_myInfo, sizeof(c_myInfo) / sizeof(c_myInfo[0]))


            private:
            const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;
            ;

            class DerivedB : public Base

            public:
            DerivedB() noexcept
            : Base(c_myInfo, sizeof(c_myInfo) / sizeof(c_myInfo[0]))


            private:
            const SomeInfo c_myInfo[3]
            "NameB1", 2.1f,
            "NameB2", 2.2f,
            "NameB2", 2.3f
            ;
            ;


            You can of course use a small, zero-overhead wrapper/adapter class instead of the c_info and c_info_len members in order to provide nicer and safer access (like begin() and end() support), but that's outside the scope of this answer.






            share|improve this answer















            You don't need any virtuals or templates here. Just add a SomeInfo* pointer and its length to Base, and provide a protected constructor to initialize them (and since there's no default constructor, it won't be possible to forget to initialize them).



            The constructor being protected is not a hard requirement, but since Base is not an abstract base class anymore, making the constructor protected prevents Base from being instantiated.



            class Base

            public:
            struct SomeInfo

            const char *name;
            const f32_t value;
            ;

            void iterateInfo()

            for (int i = 0; i < c_info_len; ++i)
            DPRINTF("Name: %s - Value: %f n", c_info[i].name,
            c_info[i].value);



            protected:
            explicit Base(const SomeInfo* info, int len) noexcept
            : c_info(info)
            , c_info_len(len)


            private:
            const SomeInfo* c_info;
            int c_info_len;
            ;

            class DerivedA : public Base

            public:
            DerivedA() noexcept
            : Base(c_myInfo, sizeof(c_myInfo) / sizeof(c_myInfo[0]))


            private:
            const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;
            ;

            class DerivedB : public Base

            public:
            DerivedB() noexcept
            : Base(c_myInfo, sizeof(c_myInfo) / sizeof(c_myInfo[0]))


            private:
            const SomeInfo c_myInfo[3]
            "NameB1", 2.1f,
            "NameB2", 2.2f,
            "NameB2", 2.3f
            ;
            ;


            You can of course use a small, zero-overhead wrapper/adapter class instead of the c_info and c_info_len members in order to provide nicer and safer access (like begin() and end() support), but that's outside the scope of this answer.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited 15 hours ago

























            answered 15 hours ago









            Nikos C.Nikos C.

            38k54171




            38k54171







            • 1





              This grows the size of every object by 1 pointer + 1 int. If you have many more instances of these objects than you do derived types, the OP's solution uses less total memory (data + code). They mention they're in a memory-constrained embedded environment. On a high-end system, the extra level of indirection is still a downside. (At least the pointer will typically be in the same cache line as the start of the data and the vtable pointer, so the extra latency is just 1 L1d cache ~load-use latency. Not an extra cache miss)

              – Peter Cordes
              3 hours ago













            • 1





              This grows the size of every object by 1 pointer + 1 int. If you have many more instances of these objects than you do derived types, the OP's solution uses less total memory (data + code). They mention they're in a memory-constrained embedded environment. On a high-end system, the extra level of indirection is still a downside. (At least the pointer will typically be in the same cache line as the start of the data and the vtable pointer, so the extra latency is just 1 L1d cache ~load-use latency. Not an extra cache miss)

              – Peter Cordes
              3 hours ago








            1




            1





            This grows the size of every object by 1 pointer + 1 int. If you have many more instances of these objects than you do derived types, the OP's solution uses less total memory (data + code). They mention they're in a memory-constrained embedded environment. On a high-end system, the extra level of indirection is still a downside. (At least the pointer will typically be in the same cache line as the start of the data and the vtable pointer, so the extra latency is just 1 L1d cache ~load-use latency. Not an extra cache miss)

            – Peter Cordes
            3 hours ago






            This grows the size of every object by 1 pointer + 1 int. If you have many more instances of these objects than you do derived types, the OP's solution uses less total memory (data + code). They mention they're in a memory-constrained embedded environment. On a high-end system, the extra level of indirection is still a downside. (At least the pointer will typically be in the same cache line as the start of the data and the vtable pointer, so the extra latency is just 1 L1d cache ~load-use latency. Not an extra cache miss)

            – Peter Cordes
            3 hours ago














            4














            You could make Base a template and take the length of your const array. Something like this:



            template<std::size_t Length>
            class Base

            public:
            struct SomeInfo

            const char *name;
            const float value;
            ;

            const SomeInfo c_myInfo[Length];

            void iterateInfo()

            //I would love to just write
            for(const auto& info : c_myInfo)
            // work with info


            ;


            And then initialize the array accordingly from each base class:



            class DerivedA : public Base<2>

            public:
            DerivedA() : Base<2> SomeInfo"NameA1", 1.1f, "NameA2", 1.2f
            ;

            class DerivedB : public Base<3>

            public:
            DerivedB() : Base<3> SomeInfo"NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f
            ;


            And then use as you normally would. This method removes the polymorphism and uses no heap allocation (e.g. no std::vector), just as user SirNobbyNobbs requested.






            share|improve this answer





























              4














              You could make Base a template and take the length of your const array. Something like this:



              template<std::size_t Length>
              class Base

              public:
              struct SomeInfo

              const char *name;
              const float value;
              ;

              const SomeInfo c_myInfo[Length];

              void iterateInfo()

              //I would love to just write
              for(const auto& info : c_myInfo)
              // work with info


              ;


              And then initialize the array accordingly from each base class:



              class DerivedA : public Base<2>

              public:
              DerivedA() : Base<2> SomeInfo"NameA1", 1.1f, "NameA2", 1.2f
              ;

              class DerivedB : public Base<3>

              public:
              DerivedB() : Base<3> SomeInfo"NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f
              ;


              And then use as you normally would. This method removes the polymorphism and uses no heap allocation (e.g. no std::vector), just as user SirNobbyNobbs requested.






              share|improve this answer



























                4












                4








                4







                You could make Base a template and take the length of your const array. Something like this:



                template<std::size_t Length>
                class Base

                public:
                struct SomeInfo

                const char *name;
                const float value;
                ;

                const SomeInfo c_myInfo[Length];

                void iterateInfo()

                //I would love to just write
                for(const auto& info : c_myInfo)
                // work with info


                ;


                And then initialize the array accordingly from each base class:



                class DerivedA : public Base<2>

                public:
                DerivedA() : Base<2> SomeInfo"NameA1", 1.1f, "NameA2", 1.2f
                ;

                class DerivedB : public Base<3>

                public:
                DerivedB() : Base<3> SomeInfo"NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f
                ;


                And then use as you normally would. This method removes the polymorphism and uses no heap allocation (e.g. no std::vector), just as user SirNobbyNobbs requested.






                share|improve this answer















                You could make Base a template and take the length of your const array. Something like this:



                template<std::size_t Length>
                class Base

                public:
                struct SomeInfo

                const char *name;
                const float value;
                ;

                const SomeInfo c_myInfo[Length];

                void iterateInfo()

                //I would love to just write
                for(const auto& info : c_myInfo)
                // work with info


                ;


                And then initialize the array accordingly from each base class:



                class DerivedA : public Base<2>

                public:
                DerivedA() : Base<2> SomeInfo"NameA1", 1.1f, "NameA2", 1.2f
                ;

                class DerivedB : public Base<3>

                public:
                DerivedB() : Base<3> SomeInfo"NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f
                ;


                And then use as you normally would. This method removes the polymorphism and uses no heap allocation (e.g. no std::vector), just as user SirNobbyNobbs requested.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited 8 mins ago









                Peter Mortensen

                14.2k1988114




                14.2k1988114










                answered 15 hours ago









                DeiDeiDeiDei

                6,40653656




                6,40653656





















                    2














                    You can use CRTP:



                    template<class Derived>
                    class impl_getDerivedInfo
                    :public Base


                    virtual const SomeInfo *getDerivedInfo(u8_t &length) override

                    //Duplicated code in every derived implementation....
                    auto& self = static_cast<Derived&>(*this);
                    length = sizeof(self.c_myInfo) / sizeof(self.c_myInfo[0]);
                    return self.c_myInfo;

                    ;


                    class DerivedA : public impl_getDerivedInfo<DerivedA>

                    public:
                    const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;
                    ;

                    class DerivedB : public impl_getDerivedInfo<DerivedB>

                    public:
                    const SomeInfo c_myInfo[3] "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f ;

                    ;





                    share|improve this answer



























                      2














                      You can use CRTP:



                      template<class Derived>
                      class impl_getDerivedInfo
                      :public Base


                      virtual const SomeInfo *getDerivedInfo(u8_t &length) override

                      //Duplicated code in every derived implementation....
                      auto& self = static_cast<Derived&>(*this);
                      length = sizeof(self.c_myInfo) / sizeof(self.c_myInfo[0]);
                      return self.c_myInfo;

                      ;


                      class DerivedA : public impl_getDerivedInfo<DerivedA>

                      public:
                      const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;
                      ;

                      class DerivedB : public impl_getDerivedInfo<DerivedB>

                      public:
                      const SomeInfo c_myInfo[3] "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f ;

                      ;





                      share|improve this answer

























                        2












                        2








                        2







                        You can use CRTP:



                        template<class Derived>
                        class impl_getDerivedInfo
                        :public Base


                        virtual const SomeInfo *getDerivedInfo(u8_t &length) override

                        //Duplicated code in every derived implementation....
                        auto& self = static_cast<Derived&>(*this);
                        length = sizeof(self.c_myInfo) / sizeof(self.c_myInfo[0]);
                        return self.c_myInfo;

                        ;


                        class DerivedA : public impl_getDerivedInfo<DerivedA>

                        public:
                        const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;
                        ;

                        class DerivedB : public impl_getDerivedInfo<DerivedB>

                        public:
                        const SomeInfo c_myInfo[3] "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f ;

                        ;





                        share|improve this answer













                        You can use CRTP:



                        template<class Derived>
                        class impl_getDerivedInfo
                        :public Base


                        virtual const SomeInfo *getDerivedInfo(u8_t &length) override

                        //Duplicated code in every derived implementation....
                        auto& self = static_cast<Derived&>(*this);
                        length = sizeof(self.c_myInfo) / sizeof(self.c_myInfo[0]);
                        return self.c_myInfo;

                        ;


                        class DerivedA : public impl_getDerivedInfo<DerivedA>

                        public:
                        const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;
                        ;

                        class DerivedB : public impl_getDerivedInfo<DerivedB>

                        public:
                        const SomeInfo c_myInfo[3] "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f ;

                        ;






                        share|improve this answer












                        share|improve this answer



                        share|improve this answer










                        answered 15 hours ago









                        OlivOliv

                        11k12058




                        11k12058





















                            2














                            One way with C++17 would be to return a "view" object representing your content list. This can then be used in a C++11 for statement. You could write a base function that converts start+len into a view, so you don't need to add to the virtual method cruft.



                            It is not that difficult to create a view object that is compatible with C++11 for statement. Alternatively, you could consider using the C++98 for_each templates that can take a begin and end iterator: Your start iterator is start; the end iterator is start+len.






                            share|improve this answer





























                              2














                              One way with C++17 would be to return a "view" object representing your content list. This can then be used in a C++11 for statement. You could write a base function that converts start+len into a view, so you don't need to add to the virtual method cruft.



                              It is not that difficult to create a view object that is compatible with C++11 for statement. Alternatively, you could consider using the C++98 for_each templates that can take a begin and end iterator: Your start iterator is start; the end iterator is start+len.






                              share|improve this answer



























                                2












                                2








                                2







                                One way with C++17 would be to return a "view" object representing your content list. This can then be used in a C++11 for statement. You could write a base function that converts start+len into a view, so you don't need to add to the virtual method cruft.



                                It is not that difficult to create a view object that is compatible with C++11 for statement. Alternatively, you could consider using the C++98 for_each templates that can take a begin and end iterator: Your start iterator is start; the end iterator is start+len.






                                share|improve this answer















                                One way with C++17 would be to return a "view" object representing your content list. This can then be used in a C++11 for statement. You could write a base function that converts start+len into a view, so you don't need to add to the virtual method cruft.



                                It is not that difficult to create a view object that is compatible with C++11 for statement. Alternatively, you could consider using the C++98 for_each templates that can take a begin and end iterator: Your start iterator is start; the end iterator is start+len.







                                share|improve this answer














                                share|improve this answer



                                share|improve this answer








                                edited 2 mins ago









                                Peter Mortensen

                                14.2k1988114




                                14.2k1988114










                                answered 12 hours ago









                                Gem TaylorGem Taylor

                                2,905222




                                2,905222





















                                    1














                                    Start with a vocabulary type.



                                    template<class T>
                                    struct span
                                    T* b = nullptr;
                                    T* e = nullptr;
                                    span( T* s, T* f ):b(s), e(f)
                                    span( T* s, size_t l ):span(s, s+l)
                                    template<size_t N>
                                    span( T(&arr)[N] ):span(arr, N)
                                    T* begin() const return b;
                                    T* end() const return e;
                                    size_t size() const return end()-begin();
                                    bool empty() const return size()==0;
                                    T& front() const return *begin();
                                    T& back() const return *(end()-1);
                                    ;
                                    // this is just here for the other array ctor:
                                    template<class T>
                                    struct span<T const>
                                    T const* b = nullptr;
                                    T const* e = nullptr;
                                    span( T const* s, T const* f ):b(s), e(f)
                                    span( T const* s, size_t l ):span(s, s+l)
                                    template<size_t N>
                                    span( T const(&arr)[N] ):span(arr, N)
                                    template<size_t N>
                                    span( T(&arr)[N] ):span(arr, N)
                                    T const* begin() const return b;
                                    T const* end() const return e;
                                    size_t size() const return end()-begin();
                                    bool empty() const return size()==0;
                                    T const& front() const return *begin();
                                    T const& back() const return *(end()-1);
                                    ;


                                    now we can talk about a span<char>.



                                    class Base

                                    public:
                                    void iterateInfo()

                                    for(const auto& info : c_mySpan)
                                    DPRINTF("Name: %s - Value: %f n", info.name, info.value);


                                    private:
                                    span<const char> c_mySpan;
                                    Base( span<const char> s ):c_mySpan(s)
                                    Base(Base const&)=delete; // probably unsafe
                                    ;


                                    now your derived looks like:



                                    class DerivedA : public Base

                                    public:
                                    const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;
                                    DerivedA() : Base(c_myInfo)
                                    ;


                                    This has overhead of 2 pointers per Base. A vtable uses 1 pointer, makes your type abstract, adds indirection, adds 1 global vtable per Derived type.



                                    Now, in theory, you could get the overhead of this down to the length of the array, and presume that the array data starts right after Base, but that is fragile, non-portable and only useful if desperate.



                                    While you may be rightly leery of templates in embedded code (as you should be of any kind of code generation; code generation means you can generate more than O(1) binary from O(1) code), the span vocabulary type is compact and should be inlined to nothing if your compiler settings are reasonably aggressive.






                                    share|improve this answer



























                                      1














                                      Start with a vocabulary type.



                                      template<class T>
                                      struct span
                                      T* b = nullptr;
                                      T* e = nullptr;
                                      span( T* s, T* f ):b(s), e(f)
                                      span( T* s, size_t l ):span(s, s+l)
                                      template<size_t N>
                                      span( T(&arr)[N] ):span(arr, N)
                                      T* begin() const return b;
                                      T* end() const return e;
                                      size_t size() const return end()-begin();
                                      bool empty() const return size()==0;
                                      T& front() const return *begin();
                                      T& back() const return *(end()-1);
                                      ;
                                      // this is just here for the other array ctor:
                                      template<class T>
                                      struct span<T const>
                                      T const* b = nullptr;
                                      T const* e = nullptr;
                                      span( T const* s, T const* f ):b(s), e(f)
                                      span( T const* s, size_t l ):span(s, s+l)
                                      template<size_t N>
                                      span( T const(&arr)[N] ):span(arr, N)
                                      template<size_t N>
                                      span( T(&arr)[N] ):span(arr, N)
                                      T const* begin() const return b;
                                      T const* end() const return e;
                                      size_t size() const return end()-begin();
                                      bool empty() const return size()==0;
                                      T const& front() const return *begin();
                                      T const& back() const return *(end()-1);
                                      ;


                                      now we can talk about a span<char>.



                                      class Base

                                      public:
                                      void iterateInfo()

                                      for(const auto& info : c_mySpan)
                                      DPRINTF("Name: %s - Value: %f n", info.name, info.value);


                                      private:
                                      span<const char> c_mySpan;
                                      Base( span<const char> s ):c_mySpan(s)
                                      Base(Base const&)=delete; // probably unsafe
                                      ;


                                      now your derived looks like:



                                      class DerivedA : public Base

                                      public:
                                      const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;
                                      DerivedA() : Base(c_myInfo)
                                      ;


                                      This has overhead of 2 pointers per Base. A vtable uses 1 pointer, makes your type abstract, adds indirection, adds 1 global vtable per Derived type.



                                      Now, in theory, you could get the overhead of this down to the length of the array, and presume that the array data starts right after Base, but that is fragile, non-portable and only useful if desperate.



                                      While you may be rightly leery of templates in embedded code (as you should be of any kind of code generation; code generation means you can generate more than O(1) binary from O(1) code), the span vocabulary type is compact and should be inlined to nothing if your compiler settings are reasonably aggressive.






                                      share|improve this answer

























                                        1












                                        1








                                        1







                                        Start with a vocabulary type.



                                        template<class T>
                                        struct span
                                        T* b = nullptr;
                                        T* e = nullptr;
                                        span( T* s, T* f ):b(s), e(f)
                                        span( T* s, size_t l ):span(s, s+l)
                                        template<size_t N>
                                        span( T(&arr)[N] ):span(arr, N)
                                        T* begin() const return b;
                                        T* end() const return e;
                                        size_t size() const return end()-begin();
                                        bool empty() const return size()==0;
                                        T& front() const return *begin();
                                        T& back() const return *(end()-1);
                                        ;
                                        // this is just here for the other array ctor:
                                        template<class T>
                                        struct span<T const>
                                        T const* b = nullptr;
                                        T const* e = nullptr;
                                        span( T const* s, T const* f ):b(s), e(f)
                                        span( T const* s, size_t l ):span(s, s+l)
                                        template<size_t N>
                                        span( T const(&arr)[N] ):span(arr, N)
                                        template<size_t N>
                                        span( T(&arr)[N] ):span(arr, N)
                                        T const* begin() const return b;
                                        T const* end() const return e;
                                        size_t size() const return end()-begin();
                                        bool empty() const return size()==0;
                                        T const& front() const return *begin();
                                        T const& back() const return *(end()-1);
                                        ;


                                        now we can talk about a span<char>.



                                        class Base

                                        public:
                                        void iterateInfo()

                                        for(const auto& info : c_mySpan)
                                        DPRINTF("Name: %s - Value: %f n", info.name, info.value);


                                        private:
                                        span<const char> c_mySpan;
                                        Base( span<const char> s ):c_mySpan(s)
                                        Base(Base const&)=delete; // probably unsafe
                                        ;


                                        now your derived looks like:



                                        class DerivedA : public Base

                                        public:
                                        const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;
                                        DerivedA() : Base(c_myInfo)
                                        ;


                                        This has overhead of 2 pointers per Base. A vtable uses 1 pointer, makes your type abstract, adds indirection, adds 1 global vtable per Derived type.



                                        Now, in theory, you could get the overhead of this down to the length of the array, and presume that the array data starts right after Base, but that is fragile, non-portable and only useful if desperate.



                                        While you may be rightly leery of templates in embedded code (as you should be of any kind of code generation; code generation means you can generate more than O(1) binary from O(1) code), the span vocabulary type is compact and should be inlined to nothing if your compiler settings are reasonably aggressive.






                                        share|improve this answer













                                        Start with a vocabulary type.



                                        template<class T>
                                        struct span
                                        T* b = nullptr;
                                        T* e = nullptr;
                                        span( T* s, T* f ):b(s), e(f)
                                        span( T* s, size_t l ):span(s, s+l)
                                        template<size_t N>
                                        span( T(&arr)[N] ):span(arr, N)
                                        T* begin() const return b;
                                        T* end() const return e;
                                        size_t size() const return end()-begin();
                                        bool empty() const return size()==0;
                                        T& front() const return *begin();
                                        T& back() const return *(end()-1);
                                        ;
                                        // this is just here for the other array ctor:
                                        template<class T>
                                        struct span<T const>
                                        T const* b = nullptr;
                                        T const* e = nullptr;
                                        span( T const* s, T const* f ):b(s), e(f)
                                        span( T const* s, size_t l ):span(s, s+l)
                                        template<size_t N>
                                        span( T const(&arr)[N] ):span(arr, N)
                                        template<size_t N>
                                        span( T(&arr)[N] ):span(arr, N)
                                        T const* begin() const return b;
                                        T const* end() const return e;
                                        size_t size() const return end()-begin();
                                        bool empty() const return size()==0;
                                        T const& front() const return *begin();
                                        T const& back() const return *(end()-1);
                                        ;


                                        now we can talk about a span<char>.



                                        class Base

                                        public:
                                        void iterateInfo()

                                        for(const auto& info : c_mySpan)
                                        DPRINTF("Name: %s - Value: %f n", info.name, info.value);


                                        private:
                                        span<const char> c_mySpan;
                                        Base( span<const char> s ):c_mySpan(s)
                                        Base(Base const&)=delete; // probably unsafe
                                        ;


                                        now your derived looks like:



                                        class DerivedA : public Base

                                        public:
                                        const SomeInfo c_myInfo[2] "NameA1", 1.1f, "NameA2", 1.2f ;
                                        DerivedA() : Base(c_myInfo)
                                        ;


                                        This has overhead of 2 pointers per Base. A vtable uses 1 pointer, makes your type abstract, adds indirection, adds 1 global vtable per Derived type.



                                        Now, in theory, you could get the overhead of this down to the length of the array, and presume that the array data starts right after Base, but that is fragile, non-portable and only useful if desperate.



                                        While you may be rightly leery of templates in embedded code (as you should be of any kind of code generation; code generation means you can generate more than O(1) binary from O(1) code), the span vocabulary type is compact and should be inlined to nothing if your compiler settings are reasonably aggressive.







                                        share|improve this answer












                                        share|improve this answer



                                        share|improve this answer










                                        answered 5 hours ago









                                        Yakk - Adam NevraumontYakk - Adam Nevraumont

                                        193k21204399




                                        193k21204399





















                                            1














                                            Okay then let's simplify all the unnecessary complications :)



                                            Your code really boils down to the following:



                                            SomeInfo.h



                                            struct SomeInfo

                                            const char *name;
                                            const f32_t value;
                                            ;

                                            void processData(const SomeInfo* c_myInfo, u8_t len);


                                            SomeInfo.cpp



                                            #include "SomeInfo.h"

                                            void processData(const SomeInfo* c_myInfo, u8_t len)

                                            for (u8_t i = 0; i < len; i++)

                                            DPRINTF("Name: %s - Value: %f n", c_myInfo[i].name, c_myInfo[i].value);




                                            data.h



                                            #include "SomeInfo.h"

                                            struct A

                                            const SomeInfo info[2] "NameA1", 1.1f, "NameA2", 1.2f ;
                                            static const u8_t len = 2;
                                            ;

                                            struct B

                                            const SomeInfo info[3] "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f ;
                                            static const u8_t len = 3;
                                            ;


                                            main.cpp



                                            #include "data.h"

                                            int
                                            main()

                                            A a;
                                            B b;
                                            processData(a.info, A::len);
                                            processData(b.info, B::len);






                                            share|improve this answer

























                                            • Given the provided example you are right.But this is just a simplification to highlight my problem. The base class is already several hundred lines of code and every derived class also has much more inside than just the const info.

                                              – SirNobbyNobbs
                                              14 hours ago






                                            • 3





                                              Well, I can imagine. All I can suggest is to use composition instead of inheritance along with simple functions. Coding can be a simple and pleasurable experience. We just complicate everything for some reason :)

                                              – Adam Zahran
                                              14 hours ago











                                            • @SirNobbyNobbs "The base class is already several hundred lines of code" - That is more of a code smell than anything that your simplified example might highlight,

                                              – Goyo
                                              4 hours ago







                                            • 1





                                              There's no point having a u8_t len = 3; member in each struct; the length of the info[] array member is already statically known as part of the derived type. @SirNobbyNobbs: What you could do is have a small inline wrapper in each of A and B that passes the right args to a common processData function. It can be virtual if you need it to be, but letting it inline into each call site when you have full type info is good. (final on the derived type functions allows that in more cases.)

                                              – Peter Cordes
                                              2 hours ago











                                            • @PeterCordes Well I thought of that. But in order to retrieve the size we would need a function. This function could either be templated or repeated. But since I'm going for simplicity and avoiding code generation here I decided a little extra u8_t in the struct will harm no one :)

                                              – Adam Zahran
                                              2 hours ago















                                            1














                                            Okay then let's simplify all the unnecessary complications :)



                                            Your code really boils down to the following:



                                            SomeInfo.h



                                            struct SomeInfo

                                            const char *name;
                                            const f32_t value;
                                            ;

                                            void processData(const SomeInfo* c_myInfo, u8_t len);


                                            SomeInfo.cpp



                                            #include "SomeInfo.h"

                                            void processData(const SomeInfo* c_myInfo, u8_t len)

                                            for (u8_t i = 0; i < len; i++)

                                            DPRINTF("Name: %s - Value: %f n", c_myInfo[i].name, c_myInfo[i].value);




                                            data.h



                                            #include "SomeInfo.h"

                                            struct A

                                            const SomeInfo info[2] "NameA1", 1.1f, "NameA2", 1.2f ;
                                            static const u8_t len = 2;
                                            ;

                                            struct B

                                            const SomeInfo info[3] "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f ;
                                            static const u8_t len = 3;
                                            ;


                                            main.cpp



                                            #include "data.h"

                                            int
                                            main()

                                            A a;
                                            B b;
                                            processData(a.info, A::len);
                                            processData(b.info, B::len);






                                            share|improve this answer

























                                            • Given the provided example you are right.But this is just a simplification to highlight my problem. The base class is already several hundred lines of code and every derived class also has much more inside than just the const info.

                                              – SirNobbyNobbs
                                              14 hours ago






                                            • 3





                                              Well, I can imagine. All I can suggest is to use composition instead of inheritance along with simple functions. Coding can be a simple and pleasurable experience. We just complicate everything for some reason :)

                                              – Adam Zahran
                                              14 hours ago











                                            • @SirNobbyNobbs "The base class is already several hundred lines of code" - That is more of a code smell than anything that your simplified example might highlight,

                                              – Goyo
                                              4 hours ago







                                            • 1





                                              There's no point having a u8_t len = 3; member in each struct; the length of the info[] array member is already statically known as part of the derived type. @SirNobbyNobbs: What you could do is have a small inline wrapper in each of A and B that passes the right args to a common processData function. It can be virtual if you need it to be, but letting it inline into each call site when you have full type info is good. (final on the derived type functions allows that in more cases.)

                                              – Peter Cordes
                                              2 hours ago











                                            • @PeterCordes Well I thought of that. But in order to retrieve the size we would need a function. This function could either be templated or repeated. But since I'm going for simplicity and avoiding code generation here I decided a little extra u8_t in the struct will harm no one :)

                                              – Adam Zahran
                                              2 hours ago













                                            1












                                            1








                                            1







                                            Okay then let's simplify all the unnecessary complications :)



                                            Your code really boils down to the following:



                                            SomeInfo.h



                                            struct SomeInfo

                                            const char *name;
                                            const f32_t value;
                                            ;

                                            void processData(const SomeInfo* c_myInfo, u8_t len);


                                            SomeInfo.cpp



                                            #include "SomeInfo.h"

                                            void processData(const SomeInfo* c_myInfo, u8_t len)

                                            for (u8_t i = 0; i < len; i++)

                                            DPRINTF("Name: %s - Value: %f n", c_myInfo[i].name, c_myInfo[i].value);




                                            data.h



                                            #include "SomeInfo.h"

                                            struct A

                                            const SomeInfo info[2] "NameA1", 1.1f, "NameA2", 1.2f ;
                                            static const u8_t len = 2;
                                            ;

                                            struct B

                                            const SomeInfo info[3] "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f ;
                                            static const u8_t len = 3;
                                            ;


                                            main.cpp



                                            #include "data.h"

                                            int
                                            main()

                                            A a;
                                            B b;
                                            processData(a.info, A::len);
                                            processData(b.info, B::len);






                                            share|improve this answer















                                            Okay then let's simplify all the unnecessary complications :)



                                            Your code really boils down to the following:



                                            SomeInfo.h



                                            struct SomeInfo

                                            const char *name;
                                            const f32_t value;
                                            ;

                                            void processData(const SomeInfo* c_myInfo, u8_t len);


                                            SomeInfo.cpp



                                            #include "SomeInfo.h"

                                            void processData(const SomeInfo* c_myInfo, u8_t len)

                                            for (u8_t i = 0; i < len; i++)

                                            DPRINTF("Name: %s - Value: %f n", c_myInfo[i].name, c_myInfo[i].value);




                                            data.h



                                            #include "SomeInfo.h"

                                            struct A

                                            const SomeInfo info[2] "NameA1", 1.1f, "NameA2", 1.2f ;
                                            static const u8_t len = 2;
                                            ;

                                            struct B

                                            const SomeInfo info[3] "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f ;
                                            static const u8_t len = 3;
                                            ;


                                            main.cpp



                                            #include "data.h"

                                            int
                                            main()

                                            A a;
                                            B b;
                                            processData(a.info, A::len);
                                            processData(b.info, B::len);







                                            share|improve this answer














                                            share|improve this answer



                                            share|improve this answer








                                            edited 1 hour ago

























                                            answered 14 hours ago









                                            Adam ZahranAdam Zahran

                                            557622




                                            557622












                                            • Given the provided example you are right.But this is just a simplification to highlight my problem. The base class is already several hundred lines of code and every derived class also has much more inside than just the const info.

                                              – SirNobbyNobbs
                                              14 hours ago






                                            • 3





                                              Well, I can imagine. All I can suggest is to use composition instead of inheritance along with simple functions. Coding can be a simple and pleasurable experience. We just complicate everything for some reason :)

                                              – Adam Zahran
                                              14 hours ago











                                            • @SirNobbyNobbs "The base class is already several hundred lines of code" - That is more of a code smell than anything that your simplified example might highlight,

                                              – Goyo
                                              4 hours ago







                                            • 1





                                              There's no point having a u8_t len = 3; member in each struct; the length of the info[] array member is already statically known as part of the derived type. @SirNobbyNobbs: What you could do is have a small inline wrapper in each of A and B that passes the right args to a common processData function. It can be virtual if you need it to be, but letting it inline into each call site when you have full type info is good. (final on the derived type functions allows that in more cases.)

                                              – Peter Cordes
                                              2 hours ago











                                            • @PeterCordes Well I thought of that. But in order to retrieve the size we would need a function. This function could either be templated or repeated. But since I'm going for simplicity and avoiding code generation here I decided a little extra u8_t in the struct will harm no one :)

                                              – Adam Zahran
                                              2 hours ago

















                                            • Given the provided example you are right.But this is just a simplification to highlight my problem. The base class is already several hundred lines of code and every derived class also has much more inside than just the const info.

                                              – SirNobbyNobbs
                                              14 hours ago






                                            • 3





                                              Well, I can imagine. All I can suggest is to use composition instead of inheritance along with simple functions. Coding can be a simple and pleasurable experience. We just complicate everything for some reason :)

                                              – Adam Zahran
                                              14 hours ago











                                            • @SirNobbyNobbs "The base class is already several hundred lines of code" - That is more of a code smell than anything that your simplified example might highlight,

                                              – Goyo
                                              4 hours ago







                                            • 1





                                              There's no point having a u8_t len = 3; member in each struct; the length of the info[] array member is already statically known as part of the derived type. @SirNobbyNobbs: What you could do is have a small inline wrapper in each of A and B that passes the right args to a common processData function. It can be virtual if you need it to be, but letting it inline into each call site when you have full type info is good. (final on the derived type functions allows that in more cases.)

                                              – Peter Cordes
                                              2 hours ago











                                            • @PeterCordes Well I thought of that. But in order to retrieve the size we would need a function. This function could either be templated or repeated. But since I'm going for simplicity and avoiding code generation here I decided a little extra u8_t in the struct will harm no one :)

                                              – Adam Zahran
                                              2 hours ago
















                                            Given the provided example you are right.But this is just a simplification to highlight my problem. The base class is already several hundred lines of code and every derived class also has much more inside than just the const info.

                                            – SirNobbyNobbs
                                            14 hours ago





                                            Given the provided example you are right.But this is just a simplification to highlight my problem. The base class is already several hundred lines of code and every derived class also has much more inside than just the const info.

                                            – SirNobbyNobbs
                                            14 hours ago




                                            3




                                            3





                                            Well, I can imagine. All I can suggest is to use composition instead of inheritance along with simple functions. Coding can be a simple and pleasurable experience. We just complicate everything for some reason :)

                                            – Adam Zahran
                                            14 hours ago





                                            Well, I can imagine. All I can suggest is to use composition instead of inheritance along with simple functions. Coding can be a simple and pleasurable experience. We just complicate everything for some reason :)

                                            – Adam Zahran
                                            14 hours ago













                                            @SirNobbyNobbs "The base class is already several hundred lines of code" - That is more of a code smell than anything that your simplified example might highlight,

                                            – Goyo
                                            4 hours ago






                                            @SirNobbyNobbs "The base class is already several hundred lines of code" - That is more of a code smell than anything that your simplified example might highlight,

                                            – Goyo
                                            4 hours ago





                                            1




                                            1





                                            There's no point having a u8_t len = 3; member in each struct; the length of the info[] array member is already statically known as part of the derived type. @SirNobbyNobbs: What you could do is have a small inline wrapper in each of A and B that passes the right args to a common processData function. It can be virtual if you need it to be, but letting it inline into each call site when you have full type info is good. (final on the derived type functions allows that in more cases.)

                                            – Peter Cordes
                                            2 hours ago





                                            There's no point having a u8_t len = 3; member in each struct; the length of the info[] array member is already statically known as part of the derived type. @SirNobbyNobbs: What you could do is have a small inline wrapper in each of A and B that passes the right args to a common processData function. It can be virtual if you need it to be, but letting it inline into each call site when you have full type info is good. (final on the derived type functions allows that in more cases.)

                                            – Peter Cordes
                                            2 hours ago













                                            @PeterCordes Well I thought of that. But in order to retrieve the size we would need a function. This function could either be templated or repeated. But since I'm going for simplicity and avoiding code generation here I decided a little extra u8_t in the struct will harm no one :)

                                            – Adam Zahran
                                            2 hours ago





                                            @PeterCordes Well I thought of that. But in order to retrieve the size we would need a function. This function could either be templated or repeated. But since I'm going for simplicity and avoiding code generation here I decided a little extra u8_t in the struct will harm no one :)

                                            – Adam Zahran
                                            2 hours ago











                                            1














                                            You can move your data into a two-dimensional array outside of the classes and have each class return an index which contains relevant data.



                                            struct SomeInfo

                                            const char *name;
                                            const f32_t value;
                                            ;

                                            const vector<vector<SomeInfo>> masterStore
                                            "NameA1", 1.1f, "NameA2", 1.2f,
                                            "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f
                                            ;

                                            class Base

                                            public:
                                            void iterateInfo()

                                            // I would love to just write
                                            // for(const auto& info : c_myInfo) ...

                                            u8_t len = 0;
                                            auto index(getIndex());
                                            for(const auto& data : masterStore[index])

                                            DPRINTF("Name: %s - Value: %f n", data.name, data.value);


                                            virtual int getIndex() = 0;
                                            ;

                                            class DerivedA : public Base

                                            public:

                                            int getIndex() override

                                            return 0;

                                            ;

                                            class DerivedB : public Base

                                            public:

                                            int getIndex() override

                                            return 1;

                                            ;

                                            DerivedA instanceA;
                                            DerivedB instanceB;
                                            instanceA.iterateInfo();
                                            instanceB.iterateInfo();





                                            share|improve this answer




















                                            • 2





                                              Why a const std::vector for compile-time-constant data with known fixed size? Seems like a job for a flat 1D std::array<SomeInfo> with each derived class knowing the right start index + offset. (GetIndex returns a std::pair<int,int>). Or a std::array<std::vector<SomeInfo>>. Or maybe implicit lengths by using a flat array of SomeInfo objects with nullptr terminators for the end of each sub-array, if you only ever want to iterate in order.

                                              – Peter Cordes
                                              3 hours ago















                                            1














                                            You can move your data into a two-dimensional array outside of the classes and have each class return an index which contains relevant data.



                                            struct SomeInfo

                                            const char *name;
                                            const f32_t value;
                                            ;

                                            const vector<vector<SomeInfo>> masterStore
                                            "NameA1", 1.1f, "NameA2", 1.2f,
                                            "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f
                                            ;

                                            class Base

                                            public:
                                            void iterateInfo()

                                            // I would love to just write
                                            // for(const auto& info : c_myInfo) ...

                                            u8_t len = 0;
                                            auto index(getIndex());
                                            for(const auto& data : masterStore[index])

                                            DPRINTF("Name: %s - Value: %f n", data.name, data.value);


                                            virtual int getIndex() = 0;
                                            ;

                                            class DerivedA : public Base

                                            public:

                                            int getIndex() override

                                            return 0;

                                            ;

                                            class DerivedB : public Base

                                            public:

                                            int getIndex() override

                                            return 1;

                                            ;

                                            DerivedA instanceA;
                                            DerivedB instanceB;
                                            instanceA.iterateInfo();
                                            instanceB.iterateInfo();





                                            share|improve this answer




















                                            • 2





                                              Why a const std::vector for compile-time-constant data with known fixed size? Seems like a job for a flat 1D std::array<SomeInfo> with each derived class knowing the right start index + offset. (GetIndex returns a std::pair<int,int>). Or a std::array<std::vector<SomeInfo>>. Or maybe implicit lengths by using a flat array of SomeInfo objects with nullptr terminators for the end of each sub-array, if you only ever want to iterate in order.

                                              – Peter Cordes
                                              3 hours ago













                                            1












                                            1








                                            1







                                            You can move your data into a two-dimensional array outside of the classes and have each class return an index which contains relevant data.



                                            struct SomeInfo

                                            const char *name;
                                            const f32_t value;
                                            ;

                                            const vector<vector<SomeInfo>> masterStore
                                            "NameA1", 1.1f, "NameA2", 1.2f,
                                            "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f
                                            ;

                                            class Base

                                            public:
                                            void iterateInfo()

                                            // I would love to just write
                                            // for(const auto& info : c_myInfo) ...

                                            u8_t len = 0;
                                            auto index(getIndex());
                                            for(const auto& data : masterStore[index])

                                            DPRINTF("Name: %s - Value: %f n", data.name, data.value);


                                            virtual int getIndex() = 0;
                                            ;

                                            class DerivedA : public Base

                                            public:

                                            int getIndex() override

                                            return 0;

                                            ;

                                            class DerivedB : public Base

                                            public:

                                            int getIndex() override

                                            return 1;

                                            ;

                                            DerivedA instanceA;
                                            DerivedB instanceB;
                                            instanceA.iterateInfo();
                                            instanceB.iterateInfo();





                                            share|improve this answer















                                            You can move your data into a two-dimensional array outside of the classes and have each class return an index which contains relevant data.



                                            struct SomeInfo

                                            const char *name;
                                            const f32_t value;
                                            ;

                                            const vector<vector<SomeInfo>> masterStore
                                            "NameA1", 1.1f, "NameA2", 1.2f,
                                            "NameB1", 2.1f, "NameB2", 2.2f, "NameB2", 2.3f
                                            ;

                                            class Base

                                            public:
                                            void iterateInfo()

                                            // I would love to just write
                                            // for(const auto& info : c_myInfo) ...

                                            u8_t len = 0;
                                            auto index(getIndex());
                                            for(const auto& data : masterStore[index])

                                            DPRINTF("Name: %s - Value: %f n", data.name, data.value);


                                            virtual int getIndex() = 0;
                                            ;

                                            class DerivedA : public Base

                                            public:

                                            int getIndex() override

                                            return 0;

                                            ;

                                            class DerivedB : public Base

                                            public:

                                            int getIndex() override

                                            return 1;

                                            ;

                                            DerivedA instanceA;
                                            DerivedB instanceB;
                                            instanceA.iterateInfo();
                                            instanceB.iterateInfo();






                                            share|improve this answer














                                            share|improve this answer



                                            share|improve this answer








                                            edited 5 mins ago









                                            Peter Mortensen

                                            14.2k1988114




                                            14.2k1988114










                                            answered 15 hours ago









                                            Tanveer BadarTanveer Badar

                                            1,6861320




                                            1,6861320







                                            • 2





                                              Why a const std::vector for compile-time-constant data with known fixed size? Seems like a job for a flat 1D std::array<SomeInfo> with each derived class knowing the right start index + offset. (GetIndex returns a std::pair<int,int>). Or a std::array<std::vector<SomeInfo>>. Or maybe implicit lengths by using a flat array of SomeInfo objects with nullptr terminators for the end of each sub-array, if you only ever want to iterate in order.

                                              – Peter Cordes
                                              3 hours ago












                                            • 2





                                              Why a const std::vector for compile-time-constant data with known fixed size? Seems like a job for a flat 1D std::array<SomeInfo> with each derived class knowing the right start index + offset. (GetIndex returns a std::pair<int,int>). Or a std::array<std::vector<SomeInfo>>. Or maybe implicit lengths by using a flat array of SomeInfo objects with nullptr terminators for the end of each sub-array, if you only ever want to iterate in order.

                                              – Peter Cordes
                                              3 hours ago







                                            2




                                            2





                                            Why a const std::vector for compile-time-constant data with known fixed size? Seems like a job for a flat 1D std::array<SomeInfo> with each derived class knowing the right start index + offset. (GetIndex returns a std::pair<int,int>). Or a std::array<std::vector<SomeInfo>>. Or maybe implicit lengths by using a flat array of SomeInfo objects with nullptr terminators for the end of each sub-array, if you only ever want to iterate in order.

                                            – Peter Cordes
                                            3 hours ago





                                            Why a const std::vector for compile-time-constant data with known fixed size? Seems like a job for a flat 1D std::array<SomeInfo> with each derived class knowing the right start index + offset. (GetIndex returns a std::pair<int,int>). Or a std::array<std::vector<SomeInfo>>. Or maybe implicit lengths by using a flat array of SomeInfo objects with nullptr terminators for the end of each sub-array, if you only ever want to iterate in order.

                                            – Peter Cordes
                                            3 hours ago











                                            1














                                            Just make the virtual function return a reference to the data directly (you need to change to vector then - not possible with array or C style array types with different sizes):



                                            virtual const std::vector<SomeInfo>& getDerivedInfo() = 0;


                                            or if pointers are the only feasible option, as a pointer range (iterators/range adapter would be preferred though if possible - more on that):



                                            virtual std::pair<SomeInfo*, SomeInfo*> getDerivedInfo() = 0;


                                            To make this last method work with range-based for loop: one way is to make a small 'range view' type that has the functions begin()/end() - essential a pair with begin()/end()



                                            Example:



                                            template<class T>
                                            struct ptr_range
                                            std::pair<T*, T*> range_;
                                            auto begin()return range_.begin();
                                            auto end()return range_.end();
                                            ;


                                            Then construct it with:



                                            virtual const ptr_range<SomeInfo> getDerivedInfo() override

                                            return std::begin(c_myInfo), std::end(c_myInfo);



                                            It is easy to make it non-template if a template is not desired.






                                            share|improve this answer





























                                              1














                                              Just make the virtual function return a reference to the data directly (you need to change to vector then - not possible with array or C style array types with different sizes):



                                              virtual const std::vector<SomeInfo>& getDerivedInfo() = 0;


                                              or if pointers are the only feasible option, as a pointer range (iterators/range adapter would be preferred though if possible - more on that):



                                              virtual std::pair<SomeInfo*, SomeInfo*> getDerivedInfo() = 0;


                                              To make this last method work with range-based for loop: one way is to make a small 'range view' type that has the functions begin()/end() - essential a pair with begin()/end()



                                              Example:



                                              template<class T>
                                              struct ptr_range
                                              std::pair<T*, T*> range_;
                                              auto begin()return range_.begin();
                                              auto end()return range_.end();
                                              ;


                                              Then construct it with:



                                              virtual const ptr_range<SomeInfo> getDerivedInfo() override

                                              return std::begin(c_myInfo), std::end(c_myInfo);



                                              It is easy to make it non-template if a template is not desired.






                                              share|improve this answer



























                                                1












                                                1








                                                1







                                                Just make the virtual function return a reference to the data directly (you need to change to vector then - not possible with array or C style array types with different sizes):



                                                virtual const std::vector<SomeInfo>& getDerivedInfo() = 0;


                                                or if pointers are the only feasible option, as a pointer range (iterators/range adapter would be preferred though if possible - more on that):



                                                virtual std::pair<SomeInfo*, SomeInfo*> getDerivedInfo() = 0;


                                                To make this last method work with range-based for loop: one way is to make a small 'range view' type that has the functions begin()/end() - essential a pair with begin()/end()



                                                Example:



                                                template<class T>
                                                struct ptr_range
                                                std::pair<T*, T*> range_;
                                                auto begin()return range_.begin();
                                                auto end()return range_.end();
                                                ;


                                                Then construct it with:



                                                virtual const ptr_range<SomeInfo> getDerivedInfo() override

                                                return std::begin(c_myInfo), std::end(c_myInfo);



                                                It is easy to make it non-template if a template is not desired.






                                                share|improve this answer















                                                Just make the virtual function return a reference to the data directly (you need to change to vector then - not possible with array or C style array types with different sizes):



                                                virtual const std::vector<SomeInfo>& getDerivedInfo() = 0;


                                                or if pointers are the only feasible option, as a pointer range (iterators/range adapter would be preferred though if possible - more on that):



                                                virtual std::pair<SomeInfo*, SomeInfo*> getDerivedInfo() = 0;


                                                To make this last method work with range-based for loop: one way is to make a small 'range view' type that has the functions begin()/end() - essential a pair with begin()/end()



                                                Example:



                                                template<class T>
                                                struct ptr_range
                                                std::pair<T*, T*> range_;
                                                auto begin()return range_.begin();
                                                auto end()return range_.end();
                                                ;


                                                Then construct it with:



                                                virtual const ptr_range<SomeInfo> getDerivedInfo() override

                                                return std::begin(c_myInfo), std::end(c_myInfo);



                                                It is easy to make it non-template if a template is not desired.







                                                share|improve this answer














                                                share|improve this answer



                                                share|improve this answer








                                                edited 1 min ago









                                                Peter Mortensen

                                                14.2k1988114




                                                14.2k1988114










                                                answered 12 hours ago









                                                darunedarune

                                                2,535826




                                                2,535826




















                                                    SirNobbyNobbs is a new contributor. Be nice, and check out our Code of Conduct.









                                                    draft saved

                                                    draft discarded


















                                                    SirNobbyNobbs is a new contributor. Be nice, and check out our Code of Conduct.












                                                    SirNobbyNobbs is a new contributor. Be nice, and check out our Code of Conduct.











                                                    SirNobbyNobbs is a new contributor. Be nice, and check out our Code of Conduct.














                                                    Thanks for contributing an answer to Stack Overflow!


                                                    • Please be sure to answer the question. Provide details and share your research!

                                                    But avoid


                                                    • Asking for help, clarification, or responding to other answers.

                                                    • Making statements based on opinion; back them up with references or personal experience.

                                                    To learn more, see our tips on writing great answers.




                                                    draft saved


                                                    draft discarded














                                                    StackExchange.ready(
                                                    function ()
                                                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56627438%2fhow-do-i-remove-this-inheritance-related-code-smell%23new-answer', 'question_page');

                                                    );

                                                    Post as a guest















                                                    Required, but never shown





















































                                                    Required, but never shown














                                                    Required, but never shown












                                                    Required, but never shown







                                                    Required, but never shown

































                                                    Required, but never shown














                                                    Required, but never shown












                                                    Required, but never shown







                                                    Required, but never shown







                                                    Popular posts from this blog

                                                    Invision Community Contents History See also References External links Navigation menuProprietaryinvisioncommunity.comIPS Community ForumsIPS Community Forumsthis blog entry"License Changes, IP.Board 3.4, and the Future""Interview -- Matt Mecham of Ibforums""CEO Invision Power Board, Matt Mecham Is a Liar, Thief!"IPB License Explanation 1.3, 1.3.1, 2.0, and 2.1ArchivedSecurity Fixes, Updates And Enhancements For IPB 1.3.1Archived"New Demo Accounts - Invision Power Services"the original"New Default Skin"the original"Invision Power Board 3.0.0 and Applications Released"the original"Archived copy"the original"Perpetual licenses being done away with""Release Notes - Invision Power Services""Introducing: IPS Community Suite 4!"Invision Community Release Notes

                                                    Canceling a color specificationRandomly assigning color to Graphics3D objects?Default color for Filling in Mathematica 9Coloring specific elements of sets with a prime modified order in an array plotHow to pick a color differing significantly from the colors already in a given color list?Detection of the text colorColor numbers based on their valueCan color schemes for use with ColorData include opacity specification?My dynamic color schemes

                                                    Ласкавець круглолистий Зміст Опис | Поширення | Галерея | Примітки | Посилання | Навігаційне меню58171138361-22960890446Bupleurum rotundifoliumEuro+Med PlantbasePlants of the World Online — Kew ScienceGermplasm Resources Information Network (GRIN)Ласкавецькн. VI : Літери Ком — Левиправивши або дописавши її