I am using private inheritance to model my has-a relationship, but my base class type is rather complicated (well, a little bit), and I would like to have a typedef for it. Is something like the following possible in C++
struct S : private typedef std::vector<int> Container {};
Currently I am doing:
template< typename Container = std::vector<int> >
struct S : private Container {};
But this
makes my class to a template class. This is not a big problem for my current application (since it is a template class anyway), but in general is not nice.
could lead to bugs, when people think they are allowed to specify their own container.
Considering that:
Inheriting from standard containers is not advisable;
Composition can replace private inheritance in most cases;
You want to control the container that will be used;
you could prefer private composition:
struct S {
using Container = std::vector<int>; // outside struct also possible
private: Container container;
};
There is no code duplication here: with inheritance, you'd just have a container sub-object whereas with composition you'd have a container member, and both would use the same code.
There is no decisive advantage of private inheritance, since other classes could not use the public members defined in the base class. The only advantage is that you can use public members in the class definition, whereas with composition, you'll have to prefix the member with the object name.
Related
Suppose I have these classes:
class A
{
// virtual methods
};
template<typename T>
class B : public A
{
void ANewMethodSpecificOfClassB(...){...};
}
I would like to add a subset of B classes into a container and from there, call ANewMethodSpecificOfClassB.
For example, given:
B<instanciation1> south_park;
B<instanciatoin2> family_guy;
suppose I want to put B<instanciation1> and B<instanciation2> in the same container (for example a vector): I cannot declare a std::vector<B> because B is not a real class, only B<instanciation1> and B<instanciation2> are.
Then I thought to define a vector using a (shared) pointer to the base class. However, doing so gives error when calling ANewMethodSpecificOfClassB because the method is not defined in the base class (and no, I can't modify the base class adding the method there).
Is there a way create a container with two different instances of a template classes and call a method that all of the instantiated classes have but not the parent class of the template class?
There are (at least) two ways around this:
You might define an intermediate class, AWithSpecificMethod:
class AWithSpecificMethod {
protected:
virtual ANewMethodSpecificOfClassB() const = 0;
};
Then have B<> descend either from A or from AWithSpecificMethod. You can do that using std::conditional<>, std::is_same<> et. al.
However, this way of solving it, at some point, creates several interfaces and immediate classes which are not true abstractions, just a notation of existence of method. Also, it's virtual => likely very slow.
You might store them in an std::variant<B<T1>, B<T2>, ...> and reconsider even if A is necessary as an interface class. This works if you know the possible types T1, T2, ... that you intend to work with (practically almost always). You can visit a variant using std::visit, which you usually pass a lambda and the variant:
std::variant<B<int>, B<char>> var;
std::visit([&](auto const& actual) {
// here actual is the concrete type
// either B<int> const& or B<char>&
}, var);
I have two related questions concerning the use of distributions inside classes.
Is there some kind of base distribution in C++ in order to use a distribution as a class member without knowing which distribution it will be? I cannot use templates (see question 2)
class Foo{
private:
// could by any distribution
std::base_distribution dist_;
};
I have another class Bar that should have a vector of Foo as a private member (std::vector<Foo>). The problem is that if Foo uses templates, then it is not possible to have a vector of different template arguments which is exactly what I want to have.
class Bar {
private:
std::vector<Foo> foo_;
};
boost::variant doesn't help either because I don't know the type of distributions. So this (for example) is not possible in my case:
class Bar{
private:
boost::variant<std::normal_distribution<>, std::uniform_real_distribution<> > dists_;
};
No, there are no base classes shared by all distribution templates. Even if there were, your intended approach wouldn't work anyway because of object slicing.
However, it should be fairly easy to create your own base class, and derive from it.
class base_distribution {};
template<typename ...Args> class normal_distribution :
public base_distribution, public std::normal_distribution<Args...> {};
template<typename ...Args> class uniform_int_distribution :
public base_distribution, public std::inform_int_distribution<Args...> {};
... and so on, for whatever distributions you want to support. You will also probably need to delegate the wrappers' constructors to their real distribution base class, for maximum transparency.
At this point, object slicing becomes a factor, so you can't just shove a base_distribution into a class, as a member, or shove it into a vector, and expect it to work. You'll have to use, at very least a
std::shared_ptr<base_distribution>
as a class member, or a container value. At this point, to wrap this up, define whatever virtual methods you need in your base_distribution class, and implement them in the template subclasses appropriately.
To my knowledge, there is no "base distribution class" or generic distribution class, in C++. You do have a RandomNumberDistribution concept, but that's obviously not the same thing.
If you want a quick-and-dirty distribution class (and I do mean dirty), I currently use something like that (.h, .cpp).
As for your second question - you might need to have your templated class inherit from a single non-templated class which you can place in your vector (you'll need to use pointer members though, to avoid data slicing).
For example, I have a class subclassing a vector
class A : private vector<int>
{
};
This make all methods in vector private in class A. I'd like to make the const methods in vector, like size(), public; and non-const methods, like push_back(), private. How to implement it?
You can use a using-declaration to (re)introduce the names of inherited functions, placing them in a public "section" will make all function overloads in the referred class with that name publicly accessible:
#include <vector>
#include <iostream>
class A : private std::vector<int>
{
public:
using vector::size;
A(vector p)
: vector(std::move(p))
{}
};
int main()
{
A a({1,2,3,4});
std::cout << a.size();
}
Note: I'm using vector, the injected-class-name of vector<int>, which is inherited to A. It is not necessary to explicitly type the template arguments.
The accepted answer of the related question "How to publicly inherit from a base class but make some of public methods from the base class private in the derived class?" shows the same technique. That should be a hint to search for an answer first ;) Note, however, that answer uses access-declarations, which have been deprecated in C++03 and I can find no sign of them in C++11 (i.e. don't use them, prefer a using-declaration as shown here).
Instead of using direct inheritance, encapsulate using the bridge pattern.
bridge pattern
You can just create a typedef to a const vector: typedef const std::vector<int> A;
This allows user to declare objects like A val; and will disable access to non-const methods. (calling them will cause compile-time error)
The disadvantage is that they aren't different types, so you can pass objects of type A to functions that expect const std::vector<int>. If having two separate types is what you require, then you have to wrap every method manually with delegation (C++ should have had strong typedefs already :-( )
I've some little question about STL iterator implementation.
why iterator defining as a struct but not as class?
what is the main reason?
It is an implementation choice. class and struct are almost the same in C++, the difference being the default access specifiers and inheritance, which are private for class and public for struct. So if a type has little need for private data members it may make more sense to implement it as a struct. But you can have exactly the same type implemented as either:
struct Iterator : IteratorBase {
SomeType x;
};
is exactly the same as
class Iterator : public IteratorBase{
public:
SomeType x;
};
This is defined in the standard, 24.2 which describes the <iterator> header, which are struct. This choice was probably made because iterators provide access to container elements and making them class would be useless, the only difference being that class has private access level by default, whereas struct has public access level.
So there were 2 choices if declaring iterators class instead of struct:
make all members public, which is useless since the same effect can be obtained by making it directly struct.
make getters, which would provide unnecessary overhead and abstraction.
Who says you that iterator is defined by struct? In standart there is nothing about it. Struct and class have only one difference - access to the elements as default. So, in struct by default access is public and in class by default access is private.
Like the best answer
class and struct is the same except the access.so use struct or class don't have many difference.
we know the C++ is include C
using struct seem simply and making a distinction between struct and class.
this is the define of iterator
struct output_iterator_tag{}
struct input_iterator_tag{}
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag{}
struct random_accessl_iterator_tag : public bidirectional_iterator_tag{}
I am quite new to real use of templates, so I have the following design question.
I am designing classes Bunch2d and Bunch4d that derive from a abstract base class Bunch:
class Bunch {virtual void create()=0;};
class Bunch2d : public Bunch {void create();};
class Bunch4d : public Bunch {void create();};
The class Bunch will contain a container, a deque or a vector (see this question: Choice of the most performant container (array)) of Particle's:
typedef Blitz::TinyVector<double,DIMENSIONS> Particle;
You therefore see my question: Bunch has to contain this container, because the "base" operations on my bunch are "dimension independant" (such a "size of the container", "clear container", etc.), so I think that the container belongs to the base class ("Bunch 'has a' container).
But this container has to know the dimensions (2 or 4) of the derived class.
So my idea would be to use a templated base class to give the typedef the correct dimension of the container:
enum Dimensions {TwoDimensions = 2, FourDimensions = 4, SixDimensions = 6};
template<Dimensions D> class Bunch
{
protected:
typedef Blitz::TinyVector<double,D> Particle;
std::deque<Particle> particles_store;
public:
virtual void create() = 0;
virtual ~Bunch();
};
class Bunch2d : public Bunch<TwoDimensions>
{
public:
~Bunch2d();
void create();
};
class Bunch4d : public Bunch<FourDimensions>
{
public:
~Bunch4d();
void create();
};
Can you give me your opinion on this design ? Would it be correct use of templates ? What about the validity of the OO concepts ? With a templated base class ?
Thanks for you help/answer/opinion.
There is one single note: different template instances (ie template classes with different types in the parameters) are of different types, and therefore are NOT a single base class.
If you need polymorphism, you will need to add a layer in your design:
class Bunch
{
public:
virtual void create() = 0;
virtual ~Bunch();
};
template <Dimensions D>
class TBunch: public Bunch
{
private:
typedef Blitz::TinyVector<double,D> Particle;
std::deque<Particle> mParticles;
};
class Bunch2d : public TBunch<TwoDimensions>
{
public:
~Bunch2d();
void create();
};
On another note: protected should be banned for attributes.
The issue is one of coupling, since protected exposes the attributes / methods to an unknown number of classes, it's no different than public in that it's impossible to reliably state how many methods will be affected by a change of implementation.
For methods, it's acceptable, because methods can be kept backward compatible (sometimes at the cost of some tricks / etc... but still).
For attributes, it's just unacceptable because an attribute is an implementation detail, not an interface, and a change cannot be made backward compatible.
Therefore I urge you not to EVER use protected for an attribute. In this particular case, it would be a good idea to factor the accesses to mParticles in the template class, without exposing the underlying implementation.
Small hint: if you cannot switch between deque and vector without breaking something beyond the class that holds them, then you have a design issue.
You'd then loose the ability to have a pointer of Bunch class pointing to either Bunch2d or Bunch4d objects at runtime, and manipulate those objects polymorphically through that pointer. If it's important to you not to loose that, don't make the base class templated. Otherwise there is no point in having virtual functions and abstract base class here at all, so then I'd recommend going just with the template.
For a start, Bunch<TwoDimensions> and Bunch<FourDimensions> are completely unrelated classes, so far as inheritance is concerned. Therefore, Bunch2d and Bunch4d have no common base class!
If this is going to be a problem for you, you'll have to do away with the templating, and have DIMENSIONS parameterised at run-time.