I need to create an array of class template in C++ but compiler doesn't allow it.
Example :
class CRefBase {
public:
virtual ~CRefBase() = 0;
};
template<class T>
class CRef : public CRefBase {
private:
T *Obj;
public:
CRef(T *Obj){ this->Obj=Obj; }
}
in main function
CRefBase *refs;
refs=new CRefBase[200]; // Error in this line : cannot allocate an object of abstract type ‘CRefBase’
I see this topic but this isn't my answer.
Thanks
Even if you were to try to instantiate a derived class, it's a terrible idea, as arrays cannot be indexed in this way- when you index a pointer to CRefBase with any index other than 0, they must only ever be CRefBase, and cannot be any derived class.
Furthermore, there is a massive bunch of exception unsafety and memory leakage in the use of new[], which is banned from all reasonable codebases. It would be safe to use something like std::vector<std::unique_ptr<CRefBase>>, and then you might actually create a program that works, if you create an object of a derived class type.
CRef is a class template, CRefBase is a (non-instantiable) abstract base class.
You're not doing what the title says:
How to create an array of templated class?
Oh, and you'll need an array of poitnters for polymorphism (and a virtual base class destructor):
CRefBase **refs = new CRefBase*[200];
for(size_t i = 0; i < 200; ++i)
refs[i] = new CRef<whatever>(pointer_to_whatever_instance);
That's it. Have a nice time managing its dynamically allocated memory.
the following code means a pure virtual function so that "CRefBase" is an abstract base class, which means that it can not be instantiated!
virtual ~CRefBase()=0;
As your question, the template supp.orts array. you can first fix your compilation problem then test it again
Related
Let's say I have a class A that inherits from its parent class B, and there is another class C that also inherits from class B. Is there a way to change this pointer of class A to class C at run time?
class A : public B {
A::someFunction() {
//can I change this pointer to class C here?
}
}
class C : public B {
...
}
You cant and you shouldn't. The reason is pretty simple. Take a look at this code,
class Base {
public:
Base() {}
virtual void SayHello() {}
};
class A_Derived : public Base {
public:
A_Derived() {}
virtual void SayHello() override { ... }
void SayAllo() { ... }
};
class B_Derived : public Base {
public:
B_Derived() {}
virtual void SayHello() override { ... }
void SayBello() { ... }
};
Now when is we assign the A_Derived class pointer to B_Derived, the compiler will allow to call the SayBello method. This is because for the compiler, its a B_Derived class pointer, it doesn't know about the actual pointer data is pointing at a data block of A_Derived (because inheritance is not compile time, its runtime). So what happens when you call SayBello using that pointer? Its gonna be undefined behavior. You see the issue?
This is why you cant do it (logically and also using C++ style casting).
Is there a way to dynamically change an object to another type?
No. The type of an object cannot change through its lifetime.
Let's say I have a class A that inherits from its parent class B, and there is another class C that also inherits from class B. Is there a way to change this pointer of class A to class C at run time?
No.
At best, you could destroy the original object, and reuse its memory to create another object. Obviously the size and alignment of the memory must be sufficient for the new type. Any reference (which includes pointers such as this in a member function) to the old object will have been invalidated by the destruction of the original object. Reuse of storage is an advanced topic which I don't recommend to beginners.
There is no valid way to do this for one simple reason - in your class inheritance structure, an object of class A cannot be also an object of class C. In C++, two objects of different types can have the same address if and only if one of the objects is a subobject of the other, which is not your case. If you cast a pointer to A to a pointer to C, the pointer will still refer to an object of type A, and dereferencing the casted pointer would result in undefined behavior.
Most probably, what you want to do is to create an object of class C from an object of class A. You can use a converting constructor or a conversion operator to implement this.
Note that if what you really want is to reuse the storage allocated for the object of type A, you will still need to destroy the object A first and then construct the object C. You will have to save any relevant data from A before destroying it to be able to construct C with the data.
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.
This is probably a simple question, please bear with me since I'm used to Java...
Lets say we have an interface:
class IDoable {
virtual void do() = 0;
};
Another class:
class Base : public IDoable {
//...
virtual void do() { ... }
};
And a last class extending our base class:
class ExtendingBase : public Base {
// some extra functionality
};
I am lost at the part if I want to make a list of IDoable objects, which can be Base objects or ExtendingBase objects. Do I have to add some method declaration of the methods in the Base class? How does this aspect work?
EDIT:
I have someList of type IDoable pointers
and if I then try to add a Base object to that list I get the error:
IDoable is an ambiguous base of Base
Same if i try to add an ExtendingBase object
IDoable is an ambiguous base of ExtendingBase
Since do is a pure virtual method, it will have to be implemented in a derived class. You can't have a vector or array of IDoable objects because you can't instantiate such an object. You can have a vector or array of pointers or references to objects though.
If you create an ExtendingBase object and call the do function, it will call the Base class' one (since ExtendingBase inherits that method).
Virtual polymorphism enters into play when you call the do() function from a base class pointer or reference: the do() function appropriate to the dynamic type of the object pointed or referenced to will be called:
class IDoable{
public:
virtual void dof()=0;
virtual ~IDoable() = default;
};
class Base:public IDoable{
public:
virtual void dof(){std::cout << "Base";}
virtual ~Base() = default;
};
class ExtendingBase:public Base{
public:
virtual void dof() { std::cout << "ExtendingBase"; }
};
int main()
{
IDoable *ptr = new Base(); // A smart pointer would be a better choice
// but for clarity's sake I'm using bare
// memory allocations here
ptr->dof(); // Walks the virtual table and calls "Base"
delete ptr;
ptr = new ExtendingBase();
ptr->dof(); // Walks the virtual table and calls "ExtendingBase"
delete ptr;
}
Also notice the use of virtual destructors: they work like normal virtual functions and thus when calling delete on a base pointer, in order to actually destruct the right type of object (i.e. to call the right destructor in the hierarchy), you will need to make it virtual.
As a sidenote: do is a reserved keyword in C++
In response to your edit: if you have a vector or a list of IDoable pointers, you can't just add a derived object to it, but you should add a pointer to a derived object. I.e. the following is wrong:
std::vector<IDoable*> vec;
vec.push_back(Base());
plus a base class remains a class (there is no interface concept in C++ as in Java) and you shouldn't inherit from a base class multiple times:
class Base:public IDoable{
...
class ExtendingBase:public Base, public IDoable <- nope
...
that would only cause issues in identifying the base subobject.
I recommend to read about the dreaded diamond problem in C++ (it's a way to solve a base class appearing multiple times in the inheritance hierarchy.. anyway a good design might probably avoid this in the first place).
if I want to make a list of IDoable objects
You cannot make an IDoable object period. It's an abstract class, it cannot be constructed directly, so you cannot have a container of them. What you can do and what you likely intend is to have a container of IDoable*:
std::vector<IDoable*> objects;
objects.push_back(new Base);
objects.push_back(new ExtendedBase);
Or to express ownership better in C++11:
std::vector<std::unique_ptr<IDoable>> objects;
Given your interface, you can already call do() on any of these objects and that will do the right thing via virtual dispatch. There is one member function you definitely want to add to your interface though:
class IDoable {
public:
virtual ~IDoable() = default; // this one
virtual void do() = 0;
};
That way, when you delete an IDoable*, you will delete the full object, not just the base interface.
You will have to implement your do() function in Base, since the function in the class IDoable is pure virtual.
If you decide to create an ExtendingBase object, the do() function will behave as it's implemented in Base, unless you override it by re-implementing it in ExtendingBase.
the first and most major of your problem is that your thinking in Java.
the words "interface" and "extending" are very Java oriented. C++ does not think this way.
for example, when someone talks about an "interface" in a C++ context, I may think he talks about the class decleration inside the .h file (as opposed to the implementation which lies in the .cpp file)
IDoable is a CLASS. period. the only difference is that it has a pure virtual functions that prohibits instansiation. other than that it behaves as a class, it can be inherited from, can hold member variables and anything else.
you just need to make sure the abstract function is overriden in some derived class in order for that class to produce objects.
thus said :
//in the stack:
Base base;
ExtendingBase eBase;
base.do();
eBase.do()
//in the heap with IDoable as pointer:
IDoable * base = new Base();
IDoable * ebase = new ExtendingBase ();
base->do();
ebase->do();
now, you may ask - how do I activate Base and ExtendingBase functions? so just like Java, you need to cast the pointer and only then call the right function.
Base* realBase = (Base*)base;
realbase->someBaseFunction();
as many things in C++, this code is a bit dangerous. you can use dynamic_cast instead.
and one last thing - do is a keyword in C++, it cannot declare a function name.
IDoable *pDo1 = new Base();
IDoable *pDo2 = new ExtendingBase();
pDo1->do();
pDo2->do();
delete pDo1;
delete pDo2;
I have an abstract base class which contains an array as well as two or more inherited classes which would like to have a slightly larger array in the base-class.
I tried to solve this by using templates:
template <int arraySize>
class Baseclass {
public:
uint16_t arr[arraySize];
};
class InheritedClass :
public Baseclass <5> {};
The issue I face now are:
Whenever I use a pointer to some Baseclass-Object, the compiler complains:
argument list for class template "Baseclass " is missing
I think I understand what is going on here: Baseclass without the template parameter isn't now a complete type - however the compiler requires one.
Therefore I wonder - is there a (better) way of achieving what I am trying to do, without allocating the array in the InheritedClass and pass pointers down to Baseclass?
Thank you in advance!
If the array is directly embedded into the base class, as in your example, then it is not possible to specify the size of that array. More precisely, changing the size of that array will require generating a completely different version of that base class for each specific array size. This will defeat the purpose, since your intent, apparently, is to have a single common base class in the hierarchy. Is it?
This is exactly the problem you run into with your template "solution". Your program doesn't have a common Baseclass anymore. Instead you have Baseclass<5>, Baseclass<10> and so on - all completely different, independent base classes. And this is not what you need, apparently.
The only way to achieve a common base class with run-time sized array in it is to store the array in the base class indirectly. I.e. declare a uint16_t * pointer in the base class and allocate the proper amount of memory at run time. Or you can simply use std::vector<uint16_t> instead of raw array.
Note that if you decide to go the pointer way, it is not absolutely required to allocate the array memory dynamically. You can simply make the actual "array memory" a member of the derived class which already "knows" the specific size
class Baseclass {
public:
uint16_t *arr;
size_t arraySize;
Baseclass(uint16_t *arr, size_t arraySize) : arr(arr), arraySize(arraySize)
{}
};
class InheritedClass : public Baseclass
{
InheritedClass() : Baseclass(arr_memory, 5)
{}
private:
uint16_t arr_memory[5];
};
So, the bottom line is, if you want the array memory management to be incapsulated entirely into Baseclass, then you have no other choice but to allocate the memory dynamically at run-time. If that is not acceptable, then you are restricted to performing memory management elsewhere and passing it down to Baseclass from outside.
You could have Baseclass derive from a non-template class, and use a pointer to that instead.
As a hack that will probably work, include a method in baseclass that reinterpret_casts this into baseclass<1>.
This relies on your ty0es being compiled into relatively sane layouts: to encourage that to happen, ensure that baseclass is pod or standard layout at the least.
While the result is undefined behaviour, in every compiler I have used it will work.
The downside? How big is your array must be transported in parallel, and you lie to other users of your class about the runtime array size. Plus it is extremely fragile: the array must be the last element of baseclass.
You are probably better off doing away with the compile time static bounds, and storing a std::vector with runtime bounds, as that will avoid undefined behavior hacks and reduce the lies per line of code.
class Baseclass {
public:
uint16_t *arr;
Baseclass(int arrlen) {
arr = new int[arrlen];
}
~Baseclass() {
delete arr;
}
};
class InheritedClass :
public Baseclass {
public:
Inherited() : Baseclass(5){
}
};
If you can, you can simply use dynamic allocation.
If you explicitly specify an argument, C++ ignores the default expression. So in your derived classes you specify your CRTP'd base's needs explicitly, but in the base you also supply a default-value calculation to be used (only) after instantiation.
So:
#include <iostream>
// instantiation specifies size explicitly, default calculation ignored
// after instantiation names in default calculation are bound correctly
template<class d,int size=sizeof d::m2/sizeof *d::m2>
struct b {
int m[size];
};
struct d: b<d,20> {
double m2[20];
};
int main() {
std::cout<<sizeof b<d>::m/sizeof *b<d>::m<<'\n';
}
I designed a series of related classes, and in order to be able to manage them I made them derive from a single abstract class.
These classes all need access to a series of shared resources, and I found myself creating a vector of pointers in each, all of them identical (they necessarily must be). It seems like making a static member in the base class would give all of the derived classes access to this vector, meaning I need only build it once (it's not going to change either after it's been built, just looked up).
My question is if this is ok, and if so, how can I then build it, without calling a 'fill the vector' method from one of the derived classes?
My thinking was to do something like
class Resource {};
enumR {RES0, RES1};
class AbstractClass
{
public:
virtual void OnInit() = 0;
void static fillVector(Resource* pResource, enumR Resourcename)
{lResource[Resourcename]=pResource;};
protected:
static vector<Resource*> lResource;
};
vector<Resource*> AbstractClass::lResource;
int main()
{
Resource res0, res1;
AbstractClass::fillVector(&res0, RES0);
AbstractClass::fillVector(&res1, RES1);
return 0;
};
Then when I instantiate an object of any class derived from AbstractClass, I'd have access to the lResource vector, which is what I want.
Would this work? Is it horrible? Is it ok?
It would work, where work = compile & run.
However, all child classes will be accessing the same static vector, which means there won't be a different copy of the static vector for each child class.
For a better explanation of what I mean read the following So thread:
Are static fields inherited?
SOLUTION:
One solution is to have your parent class a template class as follows:
template<T>
class Parent<T> {
public:
static std::vector<T> sharedResource_;
}
class ChildA : Parent<ChildA> {
}
class ChildB : Parent<ChildB> {
}
In the above code, you will get a shared resource for all instances of ChildA and another one shared between instances of ChildB.
Is it right?
Well, I think it is not considered good. One of the related discussions to this is in comments to the following SO question and also under my answer to the question:
How to do "static overloaded const" in C#?
The better solution would be to just make an object with the vectors in and then only instantiate it once and give the other classes a pointer or reference to it. Static data should be absolutely avoided unless necessary and this just isn't necessary.
You can add a static function to initialise your static vector:
class AbstractClass
{
private:
// Add this
static vector<Resource*> CreateResources();
protected:
static vector<Resource*> lResource;
};
vector<Resource*> AbstractClass::lResource = CreateResources();
vector<Resource*> AbstractClass::CreateResources()
{
vector<Resource*> resources;
resources[RES0] = new Resource();
resources[RES1] = new Resource();
return resources;
}
You could try boost::assign::list_of, something like this:
vector<Resource*> AbstractClass::lResource = list_of( &res0 )( &res1 );
I have few points here.
Your vectory probably having size of 0. This could lead to some crash. You will have to allocate it before using. You can give a static or global initialize.
Do you really want a vector? Vector is appropriate when you're using some dynamic memory allocation. The enums are static. You can give a simple count and allocate it as an array.
Do you really want a static member? Static member usually used while you're sharing it between the objects of the same class. Can you satisfy the requirement with an external objects which is local/global within the class? Also can you make static function out of the class?
Since you are creataing the vector of "resource pointer" and not reserving the spaces for object in advance ,your sysetem might crash in future. Why?
Vector create a block of memory when you insert element and uses the same block until it hits its capcity. Once it hits its capcality and you inset a new element, vector will allocate a new memory (twice as previous allocated memory) and copies all the existing elements into new memory. Since this is a vector of "pointers", it is going to invaliadate all the refernces.
What I usually do in these cases is add a middle templated layer so I have a structure like this:
Define your abstract interface:
class A
{
public:
virtual ~A(){}
virtual void f() = 0
virtual A* Clone() const = 0
}
Put the resources commonly used by the child in a template and define the boiler-plate function using CRTP if necessary keeping the necessary interface function still abstract
template<class Derived>
class A_T: public A
{
public:
virtual void f() = 0;
virtual A* Clone const
{
return new Derived(dyn_cast<Derived&>(*this))
}
void ManageRes();
private:
vector myResource;
}
Finally the different concrete classes complete the implementation and do something special with those resources if necessary
class Child: public A_T<Child>
{
public:
void foo();
}