I have some code that looks something this:
class Info {
public:
virtual bool IsHere() = 0;
virtual std::wstring GetStr() = 0;
};
class WindowsInfo : public Info {
public:
virtual std::wstring GetAnotherStr() = 0;
bool IsHere() override;
};
class AdvancedWindowsInfo : public WindowsInfo {
public:
AdvancedWindowsInfo() {}
~AdvancedWindowsInfo() {}
std::wstring GetAnotherStr() override;
std::wstring GetStr() override;
};
class InfoFactory {
public:
static Info* GetInfo();
};
class InfoManager {
public:
InfoManager();
//~InfoManager();
bool IsSomething();
private:
std::unique_ptr<Info> info;
};
InfoManager::InfoManager() {
#if WIN
info = std::make_unique<WindowsInfo>();
#else // currently no implementation Linux
info = nullptr;
#endif
}
bool InfoManager::IsSomething() {
std::unique_ptr<Info> info = InfoFactory::GetInfo();
return info && info->IsHere();
}
Info* InfoFactory::GetInfo() {
#if IS_WINDOWS
return new AdvancedWindowsInfo();
#else
return nullptr;
#endif
}
The entire code is too large (and confidential) to post here, but this snippet sums it up pretty well.
Essentially, I have a base class and some derived classes.
I also have a manager that uses a (smart) pointer to that base class.
And a Factory Method that returns the appropriate Derived object (although the signature returns a Base*).
Unfortunately, I can't get the the assignment (via the Factory Method) to work. I've tried multiple approaches but nothing works.
I tried using unique_ptr and make_unique<raw pointer>() --> it doesn't work with derived classes, only base.
I tried using unique_ptr and raw pointers --> conversion is not possible.
I tried using raw pointers (although I don't want this) and raw pointers --> it tells me that the destructor is called on the base object which is abstract. How can you call a destructor when you haven't instantiated the object (since it's an abstract class)? The compiler is contradicting itself!
Let's check the documentation for std::unique_ptr's constructors. The signature of the relevant constructor:
explicit unique_ptr( pointer p ) noexcept;
(2)
The converting constructor that converts a raw pointer to a std::unique_ptr is explicit. Among other things, this means it cannot be used for copy initialization of the form
std::unique_ptr<Info> info = InfoFactory::GetInfo();
Instead, you can use direct initialization:
std::unique_ptr<Info> info{InfoFactory::GetInfo()};
Which will allow you to perform that conversion.
While looking at this code, however, I notice that the local variable info in InfoManager::IsSomething is shadowing the class member variable InfoManager::info. If you want to change an existing std::unique_ptr so that it's now managing a new raw pointer, you might want to use reset:
info.reset(InfoFactory::GetInfo());
Ok, so I did the following:
InfoFactory::GetInfo() now returns a std::unique_ptr<Info>, as indicated by Galik
Added virtual ~Info() = default; as indicated by Nathan Pierson
Now everything seems to be working ok.
For now, I will the question unanswered as I still need to run some tests and double check some things, but basically it seems to be ok.
Thank you to everyone who made positive contibutions!
Related
I am working on a code with the following framework:
class IFirstStep // abstract interface
{
public:
virtual commonMethod1() = 0;
...
};
class FirstStepBase : public IFirstStep // Jobs common to all FirstStep's
{
public:
FirstStepBase() {}
commonMethod1() override;
...
protected:
CommonMembers;
void correctSettings()
{
somePreparations;
auto smartPtr = static_cast<std::shared_ptr<IFirstStep>>(this);
SecondStep secondStep(smartPtr);
some calculations using secondStep;
reassignment of some of commonMembers;
}
};
class FirstStep1 : public FirstStepBase
{
public:
FirstSiep1(bool fineTune)
{
commonMembers = initilizeSettings();
if (fineTune)
correctSettings();
}
private:
CommonMembers initilizeSettings() {calculate and assign commonMembers;}
};
class FirstStep2 : public FirstStepBase
...
class FirstStepN : public FirstStepBase
...
class SecondStep
{
public:
SecondStep(std::shared_ptr<IFirstStep> & firstStep) : m_firstStep(firstStep) {}
some methods which use firstStep and return some results;
firstStep itself is not changed;
};
correctSettings() is perfectly executed correcting all settings for FirstStep1 right, but crashes in MS VS debugger on exit from correctSettings() with the diagnostics:
File: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp
Line: 888
Expression: _CrtIsValidHeapPointer(block)
Looks the problem is caused by casting - code crashes even if exit is carried out just after the casting. Other types of casting, including pointer casts, were not accepted by the MS VS compiler. However, the thing works flawlessly if correctSettings() is changed as follows and an appropriate constructor is added to FirstStepBase
void correctSettings()
{
std::shared_ptr<IFirstStep> smartPtr
= <std::make_shared<FirstStepBase>>(commonMembers);
SecondStep secondStep(smartPtr);
some calculations using secondStep;
reassignment of some of commonMembers;
}
I would greatly appreciate an explanation of why the first approach fails and is it possible at all to utilize in the code this pointer rather than to generate an additional FirstStepBase object? Please, assume that there is no possibility to change interface to the SecondStep.
Thank you.
In your first approach, your this is just a raw pointer, but you tried to cast it into a `shared_pointer, which has different size, different structure.
To solve this, you can try to use boost::enable_shared_from_this, which will allow you to retrieve shared pointer of an object from its own function. Then you don't have to construct another FirstStepBase object.
You can take a look here boost_shared_from_this
You cannot type-cast a raw object pointer directly to a std::shared_ptr.
What you can do, though, is derive FirstStepBase from std::enable_shared_from_this, and then FirstStepBase can call shared_from_this() when needed, eg:
class FirstStepBase : public std::enable_shared_from_this<FirstStepBase>, public IFirstStep // Jobs common to all FirstStep's
{
...
void correctSettings()
{
...
auto smartPtr = shared_from_this(); // <-- here
SecondStep secondStep(smartPtr);
...
}
};
This only works if the FirstStep... object is being managed by a std::shared_ptr to begin with, so make sure you always use std::shared_ptr when creating your FirstStep... objects.
On the other hand, if SecondStep is not meant to outlive its associated FirstStep... object, then there is no reason to pass it a std::shared_ptr<IFirstStep> to begin with, just pass it a raw IFirstStep* pointer instead:
class SecondStep
{
private:
IFirstStep *m_firstStep;
public:
SecondStep(IFirstStep *firstStep) : m_firstStep(firstStep) {}
...
};
Passing a std::shared_ptr only makes sense if SecondStep outlives all FirstStep... references and needs to keep the object alive.
"this" is casted as a shared pointer, but in this case isn't it the raw pointer
i am pretty sure this is a simple question for a long time c++ user, this should be a pattern or the problem should be solved in any other way but given i am Python developer and a total novice with c++ i don't know how it's usually done.
Suppose that i have a class where i want to store a pointer to an object that can be of 1 of two different classes that respects an interface, for example:
class AllPlayers
{
public:
virtual void play();
};
class VlcPlayer: public AllPlayers
{
public:
virtual void play();
};
class Mplayer: public AllPlayers
{
public:
virtual void play();
};
class MyMediaPlayer
{
public:
MyMediaPLayer(int playerType);
AllPlayers m_player;
};
MyMediaPlayer::MyMediaPlayer(int PlayerType)
{
if (PlayerType == 0) {
VlcPlayer tmp_player;
m_player = static_cast<AllPlayers> (tmp_player);
}
else {
Mplayer tmp_player;
m_player = static_cast<AllPlayers> (tmp_player);
}
}
MyMediaPlayer test(0);
test.play();
First, i know this would not work and that it seems pretty normal why but how could i get this effect? i would like to have a member of a class for what i am going to use ever the same methods, implemented using a interface and i would like to avoid trying to cast to every of the derived classes every time i am going to use one of his methods.
C++ is value-based, i.e., if you create an object of a given type you really have an object of this type. This doesn't play nicely with dynamic polymorphism. To get dynamic polymorphism you use a pointer or a reference to the actual object. To also get the life-time straight you typicslly allocate the corresponding object on the stack (make sure your base class has a virtual destructor if you ever release an object of a derived type using a pointer to the base). With this, you should be all set: just call a virtual function of the base class through a pointer to rhe base: When you overridethe function in the derived class this is the function which is called.
If you write
AllPlayers m_player;
that is going to be an instance of AllPlayers and cannot be an instance of a class that derives from it.
You should instead use a pointer and allocate the class on the stack.
For example:
class MyMediaPlayer
{
public:
MyMediaPLayer(int playerType);
~MyMediaPLayer();
AllPlayers m_player;
};
MyMediaPlayer::MyMediaPlayer(int PlayerType)
{
if (PlayerType == 0) {
m_player = new VlcPlayer;
}
else {
m_player = new Mplayer;
}
}
MyMediaPlayer::~MyMediaPlayer()
{
if (0 != m_player) {
delete m_player;
m_player = 0;
}
}
As suggested by #xception use of unique_ptr may relieve you from having to write code to deallocate the instance.
As correctly pointed out by #DietmarKühl you should always declare a virtual destructor in a root class (a base class that does not itself derives from some other class) as is the case with AllPlayers.
class AllPlayers
{
public:
virtual ~AllPlayers();
virtual void play(); // note: this should probably be pure virtual.
};
The reason this will not work is colloquially known as Object Splicing. (Or, for those Harry Potter readers out there, Object Splinching)
Let's look at an example:
class Foo
{
public:
int bob;
float fred;
// Foo(const Foo& otherfoo); // implicit copy constructor
};
class Bar : public Foo
{
public:
double gabe; // gabe newell is fat
char steve; // steve jobs is thin
// Bar(const Bar& otherbar); // implicit copy constructor
};
int main()
{
Foo f;
Bar b;
f.bob = 10;
f.fred = 1.5;
b.bob = 15;
b.fred = 2.5;
b.gabe = 1.77245385091; // sqrt(pi)
b.steve = -4;
f = Foo(b);
return 0;
}
This is legal and valid. Problem is, the implicit copy constructor of Foo is called, and Foo's copy constructor knows nothing about what a Bar is. Only that it contains everything a Foo has, and some extra irrelevant crap. Because of this, only the Foo's data gets preserved; the data unique to the Bar gets spliced off.
It's important to note that this is DEFINED BEHAVIOR: it's doing EXACTLY WHAT YOU TELL IT TO. Casting between a subclass of a base class and a base class is implicit. Furthermore, the behavior of the copy constructor is implicit.
It's also important to note that, under the hood, C++ pointers and references work in the same way. It's perfectly sane to pass the Bar to Foo's copy constructor by reference, this pass by reference does not produce a copy of the object. It's the same as working with a pointer.
The actual splicing takes place as a direct result of the copy constructor biting off more than it can chew. It gets an object with more state than it expected, and its only choice is to ignore the extra state.
With python, this doesn't happen because everything is implicitly stored as a reference type. Since you only work with references (the objects themselves are abstracted away), you never have the opportunity to accidentally splice an object.
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.
I works on embedded software. Previously we don't use too many C++ features so we use memset(this,0,sizeof(child)) to initialize(zero out) a object. However it doesn't work now since we are using virtual functions. Apparently it would destroy the vtable/virtual pointer.
So my question is:
How can I initialize an object quickly and conveniently?
The class child inherits from class parent, which defines a lot virtual functions, and got many data member. If I need only to zero out all data member, any way to avoid member-by-memeber assignment in child's constructor without using memset()? or any trick to use memset without destroying vtable? (compiler-independent way)
Thank you very much.
You're asking to utilize the facilities of C++ but don't want the performance-hit of per-member initialization. Firstly, I'd ask myself if this is really the hit you're talking about. There are plenty of more bottlenecks you can be looking for than setting a member to 0.
But, if you want the features of C++ and still want the speed of memset() then I suggest you put the data for this class in a different class and initialize that to 0 and pass it to the class that is going to use it by reference.
Using placement new is definitely an option to avoid member wise zeroing out memory. Use delete[] to delete memory.
struct base{virtual ~base(){}};
struct derived : base{};
int main()
{
char *p = new char[sizeof(derived)];
memset(p, 0, sizeof(derived));
derived *pd = new (p) derived;
}
DISCLAIMER: This is a cheap and dirty hack, not very C++ish, and haters will hate it. But hey. If you gotta do what you gotta do, and what you gotta do it to is a POD, then this will work.
If you can take the data members that you want to memset and put them in their own POD, you can memset that POD. To wit (the POD in question here is the BucketOBits struct):
NOTE: It is important that the datatype you use here is a POD (Plain Old Data). For more about what this means, see this FAQ entry.
#include <cstdlib>
#include <cstring>
class Interface
{
public:
virtual void do_it() const = 0;
virtual ~Interface() {};
};
class Object : public Interface
{
public:
Object();
void do_it() const {};
private:
struct BucketOBits
{
int int_a_;
int int_b_;
int int_c_;
} bucket_;
};
Object::Object()
{
memset(&bucket_, 0, sizeof(bucket_));
};
int main()
{
Interface* ifc = new Object;
}
Even better, you can use the fact that value initialization for integral types means zero-initialization, and get rid of the memset entirely, while at the same time maybe even making your code a little faster than if you had used memset. Use default construction for BucketOBits in the constructor's initialization:
Object::Object() : bucket_()
{
};
EDIT2:
If both base & derived classes have data members that need this zero-init, then you can still use this method by giving each class it's own BucketOBits. Case in point:
#include <cstdlib>
#include <cstring>
class Interface
{
public:
virtual void do_it() const = 0;
Interface();
virtual ~Interface() {};
private:
struct BucketOBits
{
unsigned base_int_a_;
unsigned base_int_b_;
long base_int_c_;
} bucket_
};
class Object : public Interface
{
public:
Object();
void do_it() const {};
private:
struct BucketOBits
{
int int_a_;
int int_b_;
int int_c_;
} bucket_;
};
Interface::Interface() : bucket_()
{
}
Object::Object() : bucket_()
{
}
int main()
{
Interface* ifc = new Object;
}
First, you cannot avoid using the constructor, because it will be called automatically when you create the object. If you do not define a constructor yourself, the compiler will define one for you. By the time you call memset(this), which BTW you should never ever do, the constructor has already been called.
Second, in C++ initialization and assignment is not quite the same thing. Initialization is actually faster, which is why you should initialize the data members in the constructor's initialization list, rather then assign values to them in the body of the constructor.
In short, I would advise you not to fight the language.
any trick to use memset without
destroying vtable?
(compiler-independent way)
There is no way to work-around this platform independent.
The reason is that vtable not placed in a specific address, but could be in the begining of the object, or right after the last data member. So it is not portable to start calculating addresses and jump over it. Also there is the size of pointer depending on architecture etc.
For multiple inheritance it gets worse.
You should use either an initialization list (not assignment in constructor) or placement new
as Chubsdad's answer.
If I need only to zero out all data
member, any way to avoid
member-by-memeber assignment in
child's constructor without using
memset()?
You can not (and must not) avoid calling the constructor in this context, since it is the constructor that initializes the vtable pointer
Here's my problem: I have a virtual method defined in a .h file that I want to call in a class that inherits from the base class. Sadly though, the method in the derived class doesn't get called. Is there a better way to implement what I'm trying to do?
#ifndef ofxBASE_SND_OBJ
#define ofxBASE_SND_OBJ
#include "ofConstants.h"
class ofxBaseSndObj {
public:
virtual string getType(){}
string key;
};
#endif
Here's my buzz class
#ifndef OFXSO_BUZZ
#define OFXSO_BUZZ
#include "ofxBaseSndObj.h"
class ofxSOBuzz : public ofxBaseSndObj
{
public:
string getType();
};
#endif
ofxSOBuzz.cpp
string ofxSOBuzz::getType()
{
string s = string("ofxSOBuzz");
printf(" ********* returning string type %s", s.c_str()); // doesn't get called!
return s;
}
Then in another class I try to call it this way:
string ofxSndObj::createFilter(ofxBaseSndObj obj)
{
string str = obj.getType();
if(str.compare("ofxSOBuzz") == 0)
{
printf(" all is well ");
}
}
In the method above I need to be able to pass in one of many kinds of objects that all extend the ofxBaseSndObj object. Any suggestsions or pointers would be greatly appreciated. Thanks!
Change this line:
string ofxSndObj::createFilter(ofxBaseSndObj obj)
to
string ofxSndObj::createFilter(ofxBaseSndObj& obj)
What you are doing is passing by value (passing a copy).
This means you are copying the object to the function. Because the function does not know what type you are actually passing it only passes the type defined in the function declaration and thus it makes a copy of the base class (this is know as the slicing problem).
The solution is to pass by reference.
If you do not want the function to modify the object (maybe that is why you were passing by value so it could not alter the original) then pass a const reference.
class ofxBaseSndObj
{
public:
virtual string getType() const;
// If the method does not change the object mark it const
string key;
};
string ofxSndObj::createFilter(ofxBaseSndObj const& obj)
{
// allowed to call this if getType() is a const
string str = obj.getType();
if(str.compare("ofxSOBuzz") == 0)
{
printf(" all is well ");
}
}
You need to pass the instance to createFilter as a pointer (or reference) to the object. You are passing by value, and this causes the compiler to copy the derived object you use as an argument into an instance of the base class. When it does this you lose the fact that it was originally a derived type.
As written your code shouldn't actually compile since the declaration of ofxBaseSndObj::getType doesn't return anything. Did you mean for this to be an abstract method or return an empty string?
If you made it an abstract method then the compiler would complain about trying to instantiate an abstract class in your ofxSndObj::createFilter method.
This problem is called "slicing" in C++.
Making the copy constructor and operator= private is an effective way of preventing this bug from happening again.
For example:
class ofxBaseSndObj {
public:
virtual string getType(){}
string key;
private:
ofxBaseSndObj(const ofxBaseSndObj& rhs);
ofxBaseSndObj& operator=(const ofxBaseSndObj& rhs);
};
If there is no other good reason you should use C++'s built in RTTI. You can then use typeid operator. Look at your compilers documentation to turn this on if it is not on by default.
Others have addressed the slicing problem. You then ask Ok, let me say, I know I need to do something to determine the base type, but is there something more elegant than doing an enum lookup to determine the kind of inherited object?
Querying and switching on the type of the object is a poor design which misses the point of the OO approach.
Instead of
string ofxSndObj::createFilter(ofxBaseSndObj& obj)
{
string str = obj.getType();
if(str.compare("ofxSOBuzz") == 0)
{
// do ofxSOBuzz - specific thing
}
else if(str.compare("some other derived class") == 0)
{
// do stuff for other derived classes
}
// etc...
}
make the interesting behaviour the virtual function:
class ofxBaseSndObj {
public:
// get rid of getType()
virtual void HelpCreateFilter() = 0;
};
string ofxSndObj::createFilter(ofxBaseSndObj& obj)
{
// Let the derived class do it's own specialized work.
// This function doesn't need to know what it is.
obj.HelpCreateFilter();
// rest of filter creation
}
Why is this better than the original version? Because ofxSndObj::createFilter does not need modifying if future derived classes of ofxBaseSndObj are added to the system. Your version needs extending for each new derived class. If this is unclear, try to post a little more code - I can't tell from your code or class names what these functions are supposed to do.
You could use dynamic_cast or type_id