I have a base class(Base) whose constructor takes a reference as argument. In my derived class its constructor, I call the superclass-constructor and of course I need to pass a reference as argument. But I have to obtain that argument from a method of which the return type is by value...
I will give a short example:
class Base
{
public:
Base(MyType &obj) { /* do something with the obj */}
};
class Derived : public Base
{
public:
Derived(MyOtherType *otherType) :
Base(otherType->getMyTypeObj()) // <--- Here is the error because (see *)
{
// *
// getMyTypeObj() returns a value and
// the Base constructor wants a reference...
}
};
class MyOtherType
{
public:
MyType getMyTypeObj()
{
MyType obj;
obj.setData( /* blah, blah, blah... Some data */);
return obj; // Return by value to avoid the returned reference goes out of scope.
}
};
How can I solve this problem?
Change the Base class to:
class Base
{
public:
Base(const MyType &obj) { /* do something with the obj */}
};
Update: If you want to modify obj you cannot obviously have a const reference. In that case you can either:
1)Pass the parameter by value. That will have the overhead for the copy but avoid having to free it explicitly later.
2) Change MyOtherType::getMyTypeObj() to
MyType& MyOtherType::getMyTypeObj()
{
MyType* obj = new MyType();
obj->setData( /* blah, blah, blah... Some data */);
return *obj;
}
In this case, remember to delete the object after you are done with it.
Seriously? Your question has the answer in it. Change either the type of the parameter to the Base constructor, or the type of the return value of getMyTypeObj() so that the types are compatible.
The problem is caused by the GetMyTypeObj() returning a copy of 'obj', which is stack-based, so the compiler makes a temporary variable inside your constructor, the scope of which is just that Base() construction call.
It seems to me that there are two ways to solve this.
Change the Base constructor to accept a MyType object by value instead of by reference. This will copy the temporary object and solve scope problems.
Alternatively, you can make a copy of the MyType object in Derived and pass a reference to that.
class Derived : public Base
{
public:
Derived(MyOtherType *otherType) :
Base(m_myType) ,
m_myType(otherType->getMyTypeObj())
{
// ...
}
private:
MyType m_myType;
};
Option 1 is simpler and I would generally recommend it.
Option 2 is just in case some other constraint prevents you changing the Base constructor,
Related
Say i have an interace like
#include<iostream>
struct Interface
{
virtual void fun() = 0;
};
struct IType : Interface
{
void fun() override
{
std::cout<<"non const fun()";
}
};
class Type
{
private:
Interface &intr; // I can't declare intr as const i need to ascess non const fun()
public:
// I put it as a const for default value
Type(const Interface& obj = IType()) : intr{const_cast<Interface&>(obj)} // Is const_cast is safe or how to do it ?
// What is god idea to do it should i need to remove const and default value but i need a default constructor
{
intr.fun();
}
};
int main()
{
Type obj;
return 0;
}
Thanks.
Reference as class member is rarely a good idea. You need an object, passed from the outside, that will outlive your class object. You cannot use default argument and you cannot use a temporary for initialization. Typically, if you need to pass different types that inherit from an interface, this is solved with (smart) pointers.
Type(const Interface& obj = IType()) : intr{const_cast<Interface&>(obj)}
//Is const_cast is safe or how to do it ?
It depends. You can cast away constness only if the real object is not const. So this:
IType itype{};
Type {itype};
would be valid, but this:
const IType itype{};
Type {itype};
would be invalid.
Your default argument is invalid anyway, because that default is a temporary object that dies immediately once constructor finishes, which means you cannot use intr member outside of this constructor.
I'm not 100% sure if const_cast is valid on temporary or not, but that doesn't matter in this case.
The solution is to use (smart) pointers:
class Type
{
private:
std::shared_ptr<Interface> intr;
public:
Type(std::shared_ptr<Interface> obj = std::make_shared<IType>()) : intr{std::move(obj)}
{
intr.fun();
}
};
The default choice for smart pointer is std::unique_ptr, but use of reference suggests that you wanted access to object from the outside of the class as well, and std::shared_ptr will allow that.
Something goes wrong here and I can't understand what that is.
There is my class
class EmulatorCameraMng : BaseCameraManager
{
public:
EmulatorCameraMng(EmulatorCameraConfigParser & parser) : m_parser(&parser) {};
~EmulatorCameraMng() {};
public:
void load_configuration_from(const std::string & json_config_file_name);
private:
EmulatorCameraConfigParser * m_parser;
std::vector<emulator_context::EmulatorContextObj> * m_emulator_context_objects;
};
It take a parser as a param in the constructor.
Now, I need to create this EmulatorCameraMng obj and pass this parser:
EmulatorCameraConfigParser m_parser;
camera_manager::EmulatorCameraMng m_emulator_manager(m_parser);
Actually, what I want to do is pass object to another object as a param in a constructor without calling a copy constructor. So, there are two ways, by reference or by pointer, but neither of them work.
What am I doing wrong?
Within a class definition, something of the form camera_manager::EmulatorCameraMng m_emulator_manager(m_parser); is syntactically a member function declaration. You get an error there because you name an object not a type.
You will need to pass m_parser to m_emulator_manager in each constructor's member initialiser list, e.g.
class Foo {
EmulatorCameraConfigParser m_parser;
camera_manager::EmulatorCameraMng m_emulator_manager;
public:
Foo() : m_emulator_manager(m_parser) {}
}
Okay, consider the following classes:
class Object
{
public:
// Constructor
Object() :
[Initialization List]
{
...
}
...
};
class Container
{
public:
Object A;
Object B;
....
Container() :
[Initialization List]
{
}
};
I'd like to provide [access to Container and it's members] to the Objects.
My first thought was to somehow pass a reference to the current Container object to the constructors of the Objects. But I can't figure out how to do this.
I've messed around with "this", but I'm not getting anything that works. I tried something like this:
class Object
{
public:
Container& c
// Constructor
Object(Container& c_) :
c(c_)
{
...
}
...
};
class Container
{
public:
Object A;
Object B;
....
Container() :
A(Object(this))
B(Object(this))
{
}
};
My eventual goal is to be able to access Object B from inside a member method of Object A.
Does anyone have any insight on how to get closer to what I'm looking for?
Thanks!
It is not UB or bad, necessarily, to use this in an initializer list, although care is needed, and your code is perfectly valid with minor modification.
class Container;
class Object
{
public:
Container& c
// Constructor
Object(Container& c_) :
c(c_)
{
}
};
class Container
{
public:
Object A;
Object B;
Container() :
A(Object(*this))
B(Object(*this))
{
}
};
this is a pointer, you wanted a reference, and a simple de-reference will do the trick. This is perfectly legal and defined code. What's not allowed is to access any member data or functions through the pointer, because those member data or functions simply may not exist yet until the init list is finished. But it definitely is allowed to take a pointer or reference to an object during it's initializer list and pass it around.
How about just using pointers? Edit: fixed code to avoid this in initializer list.
class Container;
class Object
{
public:
Container *c;
// Constructor
Object(Container *c_) :
c(c_)
{
}
};
class Container
{
public:
Object *A, *B;
Container()
{
A = new Object(this);
B = new Object(this);
}
};
You shouldn't pass this in initializers for members of the class whose instance you're constructing, but you can pass it later, so there's two easy ways around your problem
use a setter on the object (A.setContainer(*this)) in the constructor's body
make A and B pointers, initialize them to NULL and do a A = new Object(this) in the constructor's body
As far as I know it is not possible to call the constructor of the base class. The only way I know is this:
MyClass::MyClass(/* args */) : Base(/* args */)
{
// ...
}
but this would invoke the constructor at the beginning.
Is there any way to call it somewhere else in the constructor? Something like this:
MyClass::MyClass(/* args */)
{
// ... instructions
Base::Base(/* args */);
// ... other_instructions
}
According to this What are the rules for calling the superclass constructor? question I understand there is no way but I read here and I guessed it was possible, but if I try I get:
error: invalid use of 'class Base'.
Am I doing something wrong? Is it possible to do this some way or is there any other possible solution to this need?
Thanks!
EDIT: I understand I forgot a key point: the base class is part of a framework, and therefore it would be good not to have to modify it, if possible.
If the base class constructor takes at least one argument, you could use a helper function like this:
int DoStuffBeforeCtorAndForwardInt(int arg, Foo foo)
{
DoStuff(arg, foo);
return arg;
}
MyClass::MyClass(int arg, Foo foo)
: Base(DoStuffBeforeCtorAndForwardInt(arg, foo))
{
// ...
}
If you want to default-initialize the base class, you could use the copy-ctor to copy a default initialized base class instance:
Base DoStuffBeforeCtorAndReturnDefaultBase(int arg, Foo foo)
{
DoStuff(arg, foo);
return Base();
}
MyClass::MyClass(int arg, Foo foo)
: Base(DoStuffBeforeCtorAndReturnDefaultBase(arg, foo))
{
// ...
}
Or, if Base doesn't have to be the first base class, you could derive MyClass from a helper class:
MyClass::MyClass(/* ... */)
: DoStuffHelperClass(/* ... */),
Base(/* ... */)
{
// ...
}
All of the above require that the "stuff" you do does not depend on the object that's about to be initialized (i.e. the functions can't safely be member functions and you cannot safely pass this as an argument to them either).
That means you can do some logging or similar, but then again you could also do that after the base class has been initialized.
(EDIT except with the DoStuffHelperClass solution, you can of course have members in DoStuffHelperClass, access them and what not)
Although I have to say that I can't recall ever using/needing/wanting something like that. It's quite probable that there is another (preferable) solution for what you're trying to do.
Use the base-from-member idiom to run your code before the ctor of the "real" base class (which is Base):
struct Base {
Base(string, int);
};
struct DerivedDetail {
DerivedDetail() {
value = compute_some_value();
value += more();
value += etc();
other = even_more_code(value);
}
string value;
int other;
};
struct Derived : private DerivedDetail, Base {
Derived() : Base(value, other) {}
// In particular, note you can still use this->value and just
// ignore that it is from a base, yet this->value is still private
// within Derived.
};
This works even if you don't have actual members you want in DerivedDetail. If you give more specifics on what you must do before the Base's ctor, then I can give a better example.
The base class is always fully constructed before construction of your own class begins. If you need to make a change to the state of the base class, you have to do that explicitly after it has been constructed.
Example:
MyClass::MyClass()
{
// Implicit call to Base::Base()
int result = computeSomething();
Base::setResult(result);
// ...
}
Besides the already written solutions, you can also use a static constructor function and make the contructor of MyClass private.
class QtBase{
// ...
};
class MyClass : public QtBase{
public:
// copy ctor public
MyClass(MyClass const& other);
static MyClass Create(/*args*/){
// do what needs to be done
int idata;
float fdata;
// work with idata and fdata as if they were members of MyClass
return MyClass(idata,fdata); // finally make them members
}
static MyClass* New(/*args*/){
int idata;
float fdata;
// work with idata and fdata as if they were members of MyClass
return new MyClass(idata,fdata); // finally make them members
}
private:
// ctor private
MyClass(int a_idata, float a_fdata)
: idata(a_idata)
, fdata(a_fdata)
{}
int idata;
float fdata;
};
Now you would have to create instances of MyClass either as:
MyClass obj = MyClass::Create(/*args*/);
or
MyClass* ptr = MyClass::New(/*args*/);
no, because it will not be type safe.
consider you have: a class A and a variable A.var.
now consider B inherits from A, and uses var before A was initialized. you will get a run time error! the language wants to prevent this, thus superclass constructor must be initialized first.
No, you can't do it that way, as other have described in their previous answers.
Your only chance is composition, IOW that MyClass uses Base class as a member field:
class MyClass {
public:
/** the methods... */
private:
Base* _base;
};
so you can initialize _base later, when you have the needed info. I don't know if this can apply to your scenario, anyway.
No. It is not possible, because the order of constructor calls is strictly defined by the standard. Base class ctor has to be executed before the derive class ctor can be executed.
I have some class(Window) without copy constructor (it's private). I can't understand how to init var of this class in my own class:
class MyClass
{
Window obj; // Hasn't copy constructor
public:
void init()
{
obj = Window(/* constructor params */); // [error]
obj(/* constructor params */); // [error]
}
}
Error 1: initializing argument 1 of ‘Window::Window(WindowHandle, const sf::WindowSettings&)’
Error 2: ‘NonCopyable& NonCopyable::operator=(const NonCopyable&)’ is private
But it works in this way:
Window obj(/* constructor params */);
Use an initializer list:
class MyClass
{
Window obj; // Hasn't copy constructor
public:
MyClass() :
obj(/* constructor params */)
{
}
}
This goes for references, too. You can assign any member variable in an initializer list. It only works in the constructor, though.
If you want it to work outside a constructor, you need to use a pointer:
class MyClass
{
Window *obj;
public:
void init()
{
obj = new Window(/* constructor params */);
}
}
Be sure to deallocate obj using delete in your deconstructor (and make the deconstructor virtual if necessary).
Your MyClass needs a constructor to initialize the obj member.
class MyClass
{
private:
Window obj;
public:
MyClass() : obj(/* constructor params */) // This is an initializer list
{}
};
If you need the init() function, and the Window object provides its own
init() function of some sort, you can do this:
class MyClass
{
private:
Window obj;
public:
void init()
{
obj.init(/* init params */); // Window's own init() function
}
};
If the Window class does not have anything like an init() function, you can use the heap (not recommended unless you absolutely have to):
class MyClass
{
private:
// Alternatively, we can use a smart pointer here and avoid
// managing memory ourselves.
Window* obj;
public:
MyClass() : obj(0) {}
~MyClass() { uninit(); }
void init()
{
uninit();
obj = new Window(/* constructor params */);
}
void uninit()
{
if(obj != 0)
{
delete obj;
obj = 0;
}
}
};
If the Window class declares a private copy constructor and/or copy assignment operator, then you cannot assign a new Window instance to obj.
If your copy constructor is private the class does have a copy constructor. It seems your class has bothy copy ctor and assignment op as private, which explains the second error message. The first error message has something to do with the WindowHandle class, which you haven't shown.
To make much more sense of this, we'd need to see the Window class too - does it (for example) have a default constructor?
I suppose I'm going to get thoroughly trashed for that (read till the end before going all fuming) but... assuming the constructor of windows never throws:
void MyClass::init()
{
obj::~Window(); // destroy the object
new (&obj) Window(...); // construct the object
};
I shall of course underline the not throw requirement of the constructor as if it throws you'll be left with a very muddy situation: the destructor of MyClass will call the destructor of Window regardless of whether or not the object is alive and kicking or trashed because of a failed construction, and in the latter case you get undefined behavior.
Of course, a typical thing will thus be std::unique_ptr<Window> but we have the hurdle of dynamic allocation where clearly the situation does not mandate it...
So you'd be better off using a library: Boost.Optional.
class MyClass
{
public:
private:
boost::optional<Window> obj;
};
The syntax invocation is similar to a pointer:
obj->foo();
But the one benefit is that you get inplace destruction / construction with safer semantics. Destruction is easy:
// both call ~Window() if an instance had been constructed
obj.reset();
obj = detail::none_t();
For construction use a TypedInPlaceFactory. And for assignment too... which of course clears up the previous instance (if any) first:
void MyClass::init(Arg1 arg1, Arg2 arg2)
{
obj = boost::in_place<Window>(arg1, arg2);
}
The main advantage is that if any exception is now encountered during construction, the optional object is left in the unitialized state, which is perfectly viable, and thus you need not fear undefined behavior.
So basically it's like having a dynamically allocated object owned by a smart pointer... except that the magic is that the object is not dynamically allocated, thus guaranteeing the very same performances that a "normal" object :)
I should add that the non-copyable hurdle is one of the reason behind the InPlaceFactory creation.
The whole point is not letting you clone it.
Initialize like this: Window obj(parameters of other constructor, not the copy one)
or
Window &obj = somefunctionConstructingSuchAWindow();
If Window doesn't have a copy constructor, you cannot assign another object of class Window to it. You can initialize obj only from the constructor of MyClass using an initializer list. For example:
class MyClass
{
Window obj; // Hasn't copy constructor
public:
MyClass()
: obj(/*constructor params*/)
{
/*...*/
}
}
The initialization of class members should be done on class constructor like on the following example:
class MyClass
{
public:
MyClass(/* constructor params */);
private:
Window m_obj; // Hasn't copy constructor
};
MyClass::MyClass(/* constructor params */) : m_obj(/* constructor params */)
{
}