1

I have a base class that contains some data structure, and some derived class containing exactly the same data but endowed with some extra functions, say (for the sake of concreteness):

struct Derived : public std::vector<double>
{
    // Constructors, define or inherit
    using std::vector<double>::vector;

    double norm() const;
}

Now in another part of the code, I would like to call the function norm() on an object obj of the base type std::vector<double>. Normally this would not make sense, but here:

  • Derived can be constructed from its base (the constructor was imported with a using declaration in the example),
  • Derived and itss base have precisely the same data members.

I could call:

    Derived(obj).norm()

But I’d like to avoid unnecessary copies.

Is there a way to simply and safely reinterpret object with the same underlying data structure? Or maybe a design pattern to dress data structures with (rather large) sets of functions that avoids the problem completely?

skypjack
  • 49,335
  • 19
  • 95
  • 187
Lio
  • 87
  • 7
  • 1
    You could use `static_cast`, but this would be grossly type-unsafe. This smells like an XY problem. What actual problem are you trying to solve. No, not the one stated in the question, but the problem whose answer you think involves the weird class structure that's stated in the question. – Sam Varshavchik Oct 04 '16 at 16:46
  • You are not supposed to derive from std containers because they lack certain features you may need for your program to not crash, like virtual destructors. It might be better to has_a protected vector member. To avoid this you have to either not do certain things you should be able to freely do with your class design, or cripple the entire world's c++ codebase by adding runtime overhead to the standard library. – Kenny Ostrom Oct 04 '16 at 18:29

2 Answers2

3

The idiomatic way is to provide free functions instead of member functions:

double norm(const std::vector<double>& v)
{
    // ...
}

This avoids the problem completely.

(And please, don't inherit std::vector)

Community
  • 1
  • 1
Alexandre C.
  • 55,948
  • 11
  • 128
  • 197
  • Or class static, or interface class. Also nice, you got in the don't inherit std::vector. – Kenny Ostrom Oct 04 '16 at 18:36
  • I have been thinking about this. The cons are (1) the large number of functions on one side that calls for grouping (namespace?); (2) that the base being a [non-std, thanks] container, there might be different interpretations of the contained data and corresponding sets of functions for different derived objects. – Lio Oct 04 '16 at 21:16
  • For (2), this is what the type system is for. "Different interpretations of the contained data" should imply "different types", or you are putting yourself into trouble. If there are different types, then you can overload `norm` and you have no problem. – Alexandre C. Oct 05 '16 at 06:54
  • Also, maybe try to ditch inheritance completely -- more often than not, inheritance is unnecessary (and harmful if derived objects can not be always used as base objects). Maybe one data class and many "wrapper" classes referencing the data would help. If you show more code, maybe we can help with the situation. – Alexandre C. Oct 05 '16 at 06:56
  • The title of the linked question might be what you want to say, but the page actually says it's not so bad. But you're right, free functions are the best answer. Also it's reasonable to do `using std::norm;` and overload custom math functions with standard ones. – Potatoswatter Oct 09 '16 at 07:27
  • @Potatoswatter: I found a more suitable answer to link to. – Alexandre C. Oct 09 '16 at 10:36
0

You can overload the function and that's all:

struct Derived : public std::vector<double> {
    using std::vector<double>::vector;
    inline double norm() const { return norm(*this); }
    static double norm(const std::vector<double> &) const;
}

Now you can invoke both Derived::norm(obj) and derived.norm(), where:

  • obj is a std::vector<double>
  • Derived is the class
  • derived is an object having type Derived

If you want to treat Derived as if it's its base, use its base.

skypjack
  • 49,335
  • 19
  • 95
  • 187
  • This looks very much like what I'm looking for, although for about 30 functions per `Derived` object it might be a bit of typing - or terrible awful macros? – Lio Oct 04 '16 at 21:19