inheriting vectors and initialization - c++

Am trying to inherit a class from a C++ vector and initialize it at the constructor. How do I do it? For example:
class Dataset:public std::vector<float>{
public:
Dataset(vector<float> val):*baseclass*(val){}
// bruteforce way. // Dataset(vector<float> val){//for every val[i] call push_back(val[i]);}
ofcourse there's nothing as baseclass, what I mean by the above statement is I want to initialize the vector's data with val. how do I do it without push_back ing every element?

Don't derive from std::vector<>. This class was never meant to be derived from. Use an instance of the class as a member instead:
struct Owns {
Owns() : the_vector_(42, 128) { }
private:
std::vector<float> the_vector_;
};

You could write :
Dataset(const vector<float> &val): std::vector<float>(val) {}
but in the end, you really shouldn't inherit publicly from std::vector. There are multiple hints which show that std::vector is just not meant to be derived :
No virtual destructor
No protected members
No virtual functions
You can't prevent anyone from treating your Dataset object as a std::vector<float>, because public inheritance means that Dataset is a std::vector<float>, and this will fail miserably if someone attempts to delete a Database object through a std::vector<float> pointer.
If you want to reuse std::vector, either use a private std::vector member, or inherit privately and expose what should be through using declarations.

Related

Vector in an abstract class

I believe that the question here is similar however I still need more clarification on it.
Let's say I create a vector inside an abstract class (which stores objects of another class). How would I be able to use .pushback() from another class if I can't initialise an object of an abstract class?
Obviously the easiest solution is to put the vector in another class but I need another way. I've read you can do this by storing pointers to those objects in a vector. But can somebody give me an example please?
The purpose of an abstract class is to provide an interface that is then implemented in concrete derived classes.
If you want to push items onto the vector which is a data member of the abstract class, then create an appropriate derived class and then you can create an instance of that derived class, which will thus contain a vector you can add entries to.
class Base{
public:
virtual void do_stuff()=0; // this is an abstract base class
protected:
std::vector<int> data;
};
class Derived: public Base
{
public:
void do_stuff() {
// concrete implementation
data.push_back(42); // can add values to vector inherited from base class
}
};
int main()
{
Derived d;
d.do_stuff(); // will add entries to d.data
}
However, I wonder if that is really what you are trying to achieve.
I could find some existing SO answers, but they were using C++98 code.
The right way to store a vector of abstract base classes, in that base class , is to have a vector of smart pointers to the abstract base class.
First, add the vector, and a virtual destructor
struct AbstractBase {
virtual ~AbstractBase(); // <-- this makes sure these shenanigans don't cause memory leaks
std::vector<std::unique_ptr<AbstractBase>> children;
};
Then push_back new derived classes:
struct Derived1 : public AbstractBase; // defined elsewhere
/*...*/
base.children.push_back(std::make_unique<Derived1>());
//or
auto child = std::make_unique<Derived1>();
base.children.push_back(std::move(child));
It has to be a vector of pointers allocated on the heap because vector doesn't know from the base class how big the derived classes are to store them directly.
It has to be a vector of smart pointers because when you're using pointers and heap allocation, someone has to be responsible for cleaning them up. Smart pointers do that automatically.
Lastly, that virtual destructor there in the abstract base class makes sure that even when you're using pointers that have been casted down to abstract base classes, it will call the right destructor to clean everything up.

C++ Constructor member initializer lists, Object Slicing

I have two classes
class A {
public:
virtual void doStuff() = 0;
};
class B : public A {
int x;
public:
virtual void doStuff() override { x = x*2;} //just example function
};
And another class that modify and use data from the previous
class Foo {
A a;
public:
Foo::Foo(A &a_) : a(a_) {}
};
now I create the objects, and passes to the Foo class
B b;
// edit b attributes,
Foo foo(b);
So at the argument list for the class constructor I know there is not the problem of object slicing, because is a reference, but what is the case at the moment of assign the variable a(a_)?
Since I don't know how much time the object b is going to live I need to make a secure copy. I have a lot of different derived classes from A, even derived from the derived.
Will there be a object slicing?,
Is there a solution to this, or I need to pass pointers (don't want this approach)?
This causes slicing. C++ built in polymorphism only works with pointer/reference semantics.
In fact:
class Foo {
A a;
that won't even compile, because A is not a concrete class.
To fix this, first make virtual ~A(){}; and then pass smart pointers to A around. Either unique or shared.
Failing that you can use your own bespoke polymorphism. The easiers way is to stuff a pImpl smart pointer as a private member of a class and implement copy/move semantics in the holding class. The pImpl can have a virtual interface, and the wrapping class just forwards the non-overridable part of the behaviour to it.
This technique can be extended with the small buffer optimization, or even bounded size instances, in order to avoid heap allocation.
All of this is harder than just using the built in C++ object model directly, but it can have payoff.
To see a famous example of this, examine std::function<Sig> which is a value type that behaves polymorphically.
There will be object slicing with what you currently have. You're calling the A copy-constructor in Foo's constructor, and there aren't virtual constructors.
Having a member variable of type A only reserves enough space within an instance of Foo for an instance of A. There is only dynamic binding with pointers and references (which are pointers under the hood), not with member variables.
You would have to use pointers to get around this or you could rethink whether you really need a set-up like this.
Yes, there is slicing.
There has to be slicing, because a B does not fit inside a A, but it is an A that you are storing inside the class Foo. The B part is "sliced off" to fit; hence the name.

C++ sorting container of base class pointers to derived objects

I have an std::list of base class pointers, all of which point to one of the two derived object classes. An instance of the base class is never declared, and, although the base class is not abstract, every member function is declared as virtual. Consider the code below:
class A
{
public:
A();
...
//member functions
...
protected:
int common_data_1;
std::string common_data_2;
...
};
class B: public A
{
public:
B();
//member functions
...
protected:
std::string class_B_specific_data;
...
};
class C: public A
{
public:
C();
//member functions
...
protected:
std::string class_C_specific_data;
...
};
These classes are instantiated as the appropriate base class via conditional statements and stored in an std::list by the base class pointer simultaneously in the same block of code like so:
std::list<A*> ptrList;
//conditional statements either create a B or C object
//and then that object is appended to the list
if (blahblah = true)
A* entry = new B();
else
A* entry = new C();
ptrList.append(entry);
I need to perform an insertion sort on this container of base class pointers based on an integer value that both derived classes inherit; however, in my previous attempts and upon inspection with a debugger tool, I find that my insertion sort algorithm properly makes the correct comparisons when accessing the integer that the comparison is based on, but I am unable to swap the position of the base class pointers in the std::list. I want to sort this container of pointers so that I can easily print the data in the proper order with a simple for loop.
This is clearly the result of a misunderstanding of pointer semantics, but to much avail I have been unable to find any reference or example that elucidates or solves the issue I am experiencing.
Any result that I have found either on this site or elsewhere solves this problem by using a container of the actual objects instead of a container of pointers to the objects. But, in my case, I can't do this because my code relies on the polymorphic behavior of the base class in order to have one big list of derived objects, instead of multiple lists for each derived object. Obviously, this makes calling member functions of the correct derived class extremely easy, and I would rather not redesign the entire structure of my data if I can avoid it.
If requested, I can post snippets of my code and/or the attempts that I have made to properly swap these pointer positions inside the container; however, I am unsure if this would even be helpful, since I am clearly using the wrong syntax to handle the pointers.
I appreciate any feedback; this problem has been plaguing me for the past few weeks and it is definitely time for me to step back and ask for assistance. I have a feeling that I am over-analyzing this issue, and that is most likely what is preventing me from solving the problem.
Assuming your goal is to sort an existing container, sort has a Compare comp argument that allows your to change its default behavior. To use it, you define a functor (a class that overrides operator()) that knows how you want your pointers to be compared. In this case, you want to define one that compares the common_data_1 that the pointed-to objects have.
class Comparator {
public:
bool operator(A* left, A* right) {
//You can do whatever logic you need here, here's an example:
return (a->common_data_1) < (b->common_data_2);
}
}
Then, call sort on your list:
ptrList.sort(Comparator());
I like #IanPudney's answer, though I typically use a lambda:
ptrList.sort([](A* first, A* second)
{return first->common_data_1 < second->common_data_1;}
);
Replace common_data_1 with whatever data member or function you want to use to sort.

type conversion of some elements of a vector of objects

I would like to play with a vector of objects. Let's assume I have a Base class and two derived classes: Derived_A and Derived_B.
class Base{...};
class Derived_A: public Base{};
class Derived_B: public Base{};
In the main() I create a vector of 10 objects of class Derived_A e.g.:
std::vector < Derived_A > array;
array.reserve(10);
Now, what I would like to do, is from the elements of this vector, to pick one (or several) and change its type to Derived_B. At the end, I would have a vector of some elements of class Derived_A and some of class Derived_B.
Is that possible? Or would you have a better way to do it?
No, that doesn't make any real sense. Derived_A and Derived_B are not compatible; only the Base part of each is.
If you have a std::vector<Base*> and virtual member functions, then you can [indirectly] store objects of either type, but don't go casting one to the other.
Incidentally, vectors are not arrays, and std::vector::reserve does not create elements. It only reserves memory space for them. You probably meant std::vector::resize.
You would need several things to be true, I would think:
It would have to be actually feasible to convert a Derived_A to a Derived_B, and for "sibling" classes that would be pretty unusual.
You would have to be storing using Base rather than one of the Deriveds, and even then you couldn't be storing objects but pointers/references.
The conversion (probably) wouldn't happen in-place, so you may have to remove/reinsert.
This
std::vector < Derived_A > array;
array.reserve(10);
does not define a vector of 10 objects. it defines a vector of 0 objects.
As for your question then an object of type Derived_A may not be converted to an object of type Derived_b in general case. The usual approach in this case is to define a vector of pointers to the base class. For example
std::vector<Base *> v;
and add to it pointers to objects of Derived_A and Derived_B. The derived classes should inherite virtual functions of the base class. The destructor also has to be declared as virtual.

C++ - Reach derived class variables from vector

I'm really confused, so I have to ask this. I try to write an application, but I don't know how to reach the variables of the derived class, which are in a vector in the Base class.
The code is:
class A {
public:
A() { };
std::vector<A> aVector;
void Foo();
}
class B : public A {
public:
B() { };
int j;
}
void A::Foo() {
aVector.push_back( B() );
// Here I would like to reach B::j, but only the members and variables of A comes in
aVector[0].j; // wrong
B b = aVector[0]; // no suitable user-defined conversion from "A" to "B" exists
// should I use cast? which one?
}
I'm currently learning inheritance and this kind of things through application programming, and now I'm really stuck.
I looked for other questions, but could not find any that solves my problem. If there is, and I missed, then sorry.
You need to store pointers to A so that your new B object won't get "sliced" (see explanation here) when pushed into the vector.
Also, when you want to use specifically a child method / variable on a pointer from the base class, you need to cast it into the proper type
std::vector<A*> aVector;
aVector.push_back(new B());
B* b = (B*)aVector[0];
cout << b->j;
// remember to delete the content of aVector
Casting an object like this can be dangerous if you are not 100% sure that it is of the type you're casting it in.
See this thread for more information on casting (C style, dynamic_cast and static_cast)
Since the vector is declared to hold objects of type A, when you push a B in to the vector, all the B-ness is stripped away from the object that's stored in the vector. This is known as the slicing problem.
When you later try to access the B elements of the objects stored in the vector you can't because they simply don't exist. You don't have a vector of B objects -- you have a vector of A objects.
In order to solve this problem, you need to store A objects not by value, but by reference or by pointer. You can't store references in a vector, so this leaves you with pointers.
This has nothing to with vectors. If B derives from A then the following code:
A a;
B b = a;
is an error (unless there is some method to convert).
This is correct - your vector items you should be able to handle uniformly. If this means the code that uses the vector expects all items to be B then just make a vector<B>. If not, then you have no business converting an A to a B anyway.
You should never try to access derived class members from the base class. The base class should be agnostic about the implementation details of the derived class. What you are doing is not polymorphic. In other words your B instances cannot act like A instances, because you provided no virtual methods and overrode no virtual methods.
The entire design and approach is incorrect. A::Foo() should be a virtual method (Perhaps even abstract). And you should be doing the work in B::Foo().
And another thing, you shouldn't hold a vector of just plain old A. It should be pointers to A. So std::Vector. And that member should be prefixed with the letter m, to indicate it's a member variable of the class. So std::vector mSomething;