Will someone please point me in the correct directions. I want a "static" (singular instance) std::list, so the std::list is shared within all objects having an instance of the "Container" structure seen below. However, all other elements within the structure are to remain unique to each instance.
Where am i to place the keyword "static" for the derived std::list?
Note the keyword "static" below is misplaced, as i simply don't know where it should be in this case.
struct Container : public static std::list<int>
{
public:
Container()
{}
~Container()
{}
list<int*> Handles;
}; // struct
You don't need inheritance here; the best way to do it is to have a static member:
struct Container {
static std::list<int> list_;
}
There is no static inheritance as well, so I would propose to implement your own get, insert, remove methods that would modify internal static list.
You should not inherit from std::list; instead it seems like you want a single static member instead:
class Container
{
static std::list<int> SingleList;
// ...
}
By making a member variable static there is only one single instance of that variable, shared between all instance of the class it's declared in. Just like you want.
I believe a static member works for your case.
struct Container
{
public:
Container()
{}
~Container()
{}
public:
static std::list<int*> Handles;
}; // struct
As others have said, inheriting from standard containers is bad, and the reason this is bad is because standard containers have no virtual destructor defined. This means that upon destruction, you will not be destroying the derived object properly, when trying to destroy it through a pointer to base.
Base* b = new derived();
// do stuff
delete b; // will not destroy derived properly because base has no virtual destructor.
Related
I have the following class definitions:
class BaseHandle { /* Lots of things */ };
class VertexHandle : public BaseHandle {
/* Only static members and non-virtual functions, default dtor */ };
class EdgeHandle : public BaseHandle { /* Dito */ };
class FaceHandle : public BaseHandle { /* Dito */ };
All classes have no virtual functions or bases.
The derived classes only derive from BaseHandle and do not add any non-static members, nor non-default dtors.
I want to save Vertex-, Edge- and FaceHandles in the same vector:
std::vector<BaseHandle*> handles;
But it doesn't work, if I retrieve the BaseHandle object and want to dynamic_cast them to the derived object it fails, because the classes are not polymorphic (that's my explanation perhaps I'm wrong).
How could I achieve a common vector of BaseHandles? I should mention, that I can't change the class defintions because they are part of a third party library.
You need to have a virtual destructor in your parent class for it to be used polymorphically
class BaseHandle
{
public:
virtual ~BaseHandle();
...
};
That's because dynamic_cast works with the RTTI (RunTime Type Information) which is only available if your class has at least one virtual member function
And this will also prevent resource leaks, otherwise only the parent class part of your instance would be destroyed
Workaround
You can use an std::vector of std::shared_ptr, not only will you avoid memory leaks by not having to call new and delete by hand but that smart pointer also has a magic property (it stores the deleter to call on destruction based on the way it was constructed) that solves your problem:
int main()
{
std::vector<std::shared_ptr<BaseHandle>> shared_vec;
shared_vec.push_back(std::make_shared<VertexHandle>());
} // At the end of scope all destructors are called correctly
If you don't have access to c++11 you could use boost::shared_ptr
You could store
struct thing
{
enum Type { vertex, edge, face };
Type type;
union
{
VertexHandle * vh;
EdgeHandle * eh;
FaceHandle * fh;
};
};
but it's basically a mess ... are you sure you want to do this? It looks like you are storing multiple types in a single array despite the fact that there is no way to use them polymorphically, so is there actually a good reason to have only one array, and not three?
Following on from a comment by Kerrek. You could "create your own, parallel class hierarchy and add each of those types as a member". For example:
class MyBaseHandle {
public:
virtual ~MyBaseHandle(){}
virtual Box getBoundingBox() const = 0;
};
class MyEdgeHandle : public MyBaseHandle {
std::unique_ptr<EdgeHandle> handle_;
public:
MyHandle(std::unique_ptr<EdgeHandle> handle) : handle_(std::move(handle)) {}
Box getBoundingBox() const override;
};
Then you can dynamic_cast if you want to. But I would try and avoid using dynamic_cast at all. Add virtual methods in your parallel class hierarchy that do what you need. For example I've added a virtual getBoundingBox function to the base class that you can then specialize for your particular kinds of handle:
Box MyEdgeHandle::getBoundingBox() const {
// Get data from EdgeHandle
auto v1 = handle_->getVertex1();
auto v2 = handle_->getVertex2();
// create box from edge data...
return box;
}
Live demo
If all classes derived from BaseHandle only use single-inheritance from BaseHandle (plus maybe inheritance from empty classes with trivial dtor, which are subject to empty-baseclass-optimization) and don't add anything but non-virtual functions and static members, and all derived classes use the default dtor or equivalent, you can just static_cast to the target.
Though be aware that there is no way to know which of the derived classes, if any, it actually was.
For any reason, I have an object created by a static method which calls the private constructor. (It isn't a singleton)
I want to make a new object derives from the first one, which have more members and functions.
But it's problematic, becuase the static method returns a firstObject* object, so a creation with downcasting of the secondObject* will make a memory overflow.
What should I do? I have an access to the first object's code, but it is impossible to change its constructor (If I change it, I will have to change a huge written code).
EDIT:
Thank to all responders. I can change the constructor to be protected.
Make sure your constructor is at least protected so that child classes can use it.
Not sure what you fear about memory overflow but this:
class Base {
public:
static Base* getInstance();
virtual ~Base() {};
protected:
Base() {};
};
class Derived : public Base {};
// Implementation
Base* Base::getInstance() { return new Derived(); }
int main() {
Base::getInstance();
};
Works perfectly.
Now I would advise you against returning a raw pointer in that situation (std::unique_ptr would be way better) but that's probably off-topic.
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();
}
This is probably best shown with example code. The following fails to compile with g++:
struct Base {
};
struct Derived : public Base {
};
struct Container {
Derived data_;
};
int main(void) {
Base Container::*ptr = &Container::data_;
}
I get the following error: invalid conversion from 'Derived Container::*' to Base Container::*'.
Is this not allowed by the language? Is this a compiler bug? Am I using the wrong syntax?
Please help!
Some background as to why I'm trying to do this: I have several member data pieces that I want to use primarily as their derived types, but I want to be able to populate them through some common code. Data will be coming in an arbitrary order and have a string label that I would use to select the appropriate member data to populate. I was planning on creating a std::map<std::string, Base Container::*> to assign data to each member through a common interface. I'd like to avoid have a giant if else construct to find the right member data.
This is not a compiler bug, you can't do that. (But you can assign a Base::* to a Derived::*).
I don't see any good reason for the limitation (excepted that to handle the case of multiple inheritance, that would complicate even more the representation of a member pointer).
There are a lot of fairly complex, some not-well-explained, and a few flat wrong answers in this thread.
But the problem, it seems to me, is that there simply isn't a Base member within Container -- there is a Derived member. You can't do this:
Base Container::*ptr = &Container::data_;
...for the same reason you can't do this:
int a;
long* pl = &a;
In the second example, the object isn't a long, it's an int. Similarly, in the first example the object isn't a Base, it's a Derived.
As a possibly tangential point, it seems to me like what you really want to do is have Base be an abstract class, and have Container have a Base* rather than a Derived member.
Pointers to members in C++ are not really pointers but more like offsets to given member and are specific to the type, so what you are trying to do is not really supported.
Here's a decent discussion here on Stackoverflow C++: Pointer to class data member.
You just need to write:
Base* ptr = &container.data_;
but container has to be an instance of Container, so you have to create one variable of that type somewhere.
You cannot convert C::*A to C::*B even if there is a conversion possible between A and B.
However, you can do this:
struct Base
{
virtual ~Base() {}
virtual void foo() { std::cout << "Base::foo()\n"; }
};
struct Derived : Base
{
void foo() { std::cout << "Derived::foo()\n"; }
};
struct Bar
{
Base* x;
Bar() : x(new Derived) {}
};
int main()
{
Bar b;
Base* Bar::*p = &Bar::x;
(b.*p)->foo();
}
You would have to static_cast to do this conversion as seen in 5.3.9/9. This reason for this is that it acts as a static_cast from parent object pointer to child object pointer would. In other words, putting a pointer to a derived member into a pointer-to-parent-member would allow you to possibly access a non-existent derived member from a parent object or pointer. If the standard allowed this automatically it would be easy to mess up and try to access a child member on a class that isn't of the appropriate child type (that contains said member).
Without more information it sounds like you need a different/better constructor/set interface in your Base class rather than trying to use pointers-to-member here.
I think what you want is a 'container', ie a struct which just has pointers:
struct Container{
Base* derivedAdata_;
Base* derivedBdata_;
...
};
Now each of the members you know to be of a specific type (ie DerivedA, DerivedB etc) so you can down-cast them later.
But first you are receiving data (in arbitrary order), but with a string name, so you should have a map:
std::map<std::string, Base* Container::*>
And you must have already populated the map:
myMap["DerivedA"] = &Container::derivedAdata;
...
Now data arrives and you start populating the container:
instance.*(myMap[key]) = factory(key, data);
myMap[key] picks the right member of the container and factory(key,data) creates instances.
btw you could just have a map as your container anyway:std::map<std::string, Base*>
Regarding the original issue, you can do this using pointer to functions, instead of introducing base classes.
class Container {
public:
void set(std::string const& label, std::string const& value);
void setName(std::string const& value) { _name = value; }
void setAge(std::string const& age) {
_age = boost::lexical_cast<size_t>(age);
}
private:
std::string _name;
size_t _age;
};
How to implement set then ?
// container.cpp
typedef void (Container::*SetterType)(std::string const&);
typedef std::map<std::string, SetterType> SettersMapType;
SettersMapType SettersMap =
boost::assign::map_list_of("name", &Container::setName)
("age", &Container::setAge);
void Container::set(std::string const& label, std::string const& value) {
SettersMapType::const_iterator it = SettersMap.find(label);
if (it == SettersMap.end()) { throw UnknownLabel(label); }
SetterType setter = it->second;
(this->*setter)(value);
}
struct Container {
Derived data_;
};
int main(void)
{
Base Container::*ptr = &Container::data_;
}
The first problem is that Container doesn't have a member called ptr
Container container_object;
Base *ptr = container_object.data_;
Would work. Note that there needs to be a container object to create the data_ member and it would need to be made public.
The alternative would be for derived::data_ to be a static member.
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.