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
Related
Consider I want to wrap some library code inside an object. That library needs to be set up and initialized by calling some function inside the constructor of that wrapper class.
The librarie's "objects" then diverge into creating more, different "objects" that the wrapper class wraps in form of yet another wrapper object that should be a plain member of that class.
But as far as I see it, members of classes can only be initialized or created by calling their constructor in the initalizer list of the constructor. The execution of these bits of code preceed the constructor of the actual class that does the initialization of the library and its environment, making it impossible for me to actually initialize that member object as a member and instead force me to initialize it as a pointer to the 2nd wrapper, because its constructor must be called manually within the first constructor's code.
Example:
class A {
public:
A() {
if(!wrapped_library_init()) {
exit(CRITICAL_ERROR);
}
ptr_to_some_library_metadata *a = library_function(); /*Needs to
be called after wrapped_library_init() or needs a pointer to some
wrapped object created inside this constructor */
//initialize b
}
private:
B b; //Wants to be a member but can not
};
class B {
B(ptr_to_some_library_metadata *a);
}
Member objects can only be constructed in the member initializer list. There are a few techniques which can be used to make it possible to initialize an object, though:
Use a helper [lambda] function doing the necessary extra work before return a suitable object. For example:
A()
: B([]{
if (!wrapped_library_init()) {
exit(CRITICAL_ERROR);
}
return library_function();
}()) {
}
You can delay construction by using a union with just the appropriate member. When using this technique the member needs to be explicitly destructed, for example:
class A {
union Bu { B b };
Bu b;
public:
A() {
if (!wrapped_library_init()) {
exit(CRITICAL_ERROR);
}
new(&b.b) B(library_function());
}
~A() {
b.b.~B();
}
// ...
};
I'd personally use the first approach. However, there are cases when using a union to delay construction is helpful.
Initializer lists are there to use another constructor than the default constructor.
But nothing impedes you for creating a custom function that will initialize b:
class A {
public:
A():b(init()) {
}
private:
B b; //Wants to be a member but can not
static B init()
{
if(!wrapped_library_init()) {
exit(CRITICAL_ERROR);
}
ptr_to_some_library_metadata *a = library_function(); /*Needs to
be called after wrapped_library_init() or needs a pointer to some
wrapped object created inside this constructor */
return B(a);
}
};
Wrap your library inside a class:
class LibraryWrapper
{
public:
LibraryWrapper()
{
if(!wrapped_library_init()) {
exit(CRITICAL_ERROR);
}
lib_data.reset(library_function()); /*Needs to
be called after wrapped_library_init() or needs a pointer to some
wrapped object created inside this constructor */
}
//~LibraryWrapper() {/**/}
//LibraryWrapper(const LibraryWrapper&) {/**/} // =delete; ?
//LibraryWrapper& operator=(const LibraryWrapper&) {/**/} // =delete; ?
//private: // and appropriate interface to hide internal
std::unique_ptr<ptr_to_some_library_metadata, CustomDeleter> lib_data;
};
class B {
public:
explicit B(ptr_to_some_library_metadata *a);
// ...
};
And use extra member or inheritance:
class A
{
public:
A() : b(lib.lib_data.get()) {}
private:
LibraryWrapper lib; // placed before B
B b;
};
I have two classes. In the class A constructor, I am calling the constructor of class B. However, while creating class B object, I want to pass the QSCOPED pointer of the class A object. In short, instead of this pointer, I want to pass the QSCOPED pointer. How can I do so?
class B;
class A
{
class A();
};
A::A()
{
QScopedPointer<B> m_p_B( new B(this));
}
My requirement is that instead of passing this pointer, I want to pass the QSCOPED pointer of the class A. Basically a QSCOPED pointer of this pointer. How can I do so?
Something like this:
It's not needed to pass QScopedPointer in the constructor, it will be created in the initializer list.
#include<QScopedPointer>
class B
{
public:
B(A* a) : ma(a) {}
private:
QScopedPointer<A> ma;
}
I have an abstract class and two concrete subclasses (Store), both with a pointer to another concrete subclass which is derived from an abstract class (Factory). Below is the code for the Store. I wanted to prevent memory leaks, so I started to write the copy control. I can't instantiate a new Factory however, because I don't know upfront what type it will be. What is a good practice to circumvent this? I could write the copy control in the concrete Stores, but then I have duplicate code.
I also tried to work with smart pointers instead, but there I find another difficulty. The snippet myFactory = std::make_shared<AbstractFactory>(ConcreteFactoryA()); apparently creates an AbstractFactory first, and then fills it with a ConcreteFactoryA. However, as the name suggests, AbstractFactory cannot be instantiated, as the compiler is telling me. Can you use shared_ptrs with abstract classes?
Code with plain pointers:
#pragma once
#include "AbstractFactory.h"
class AbstractStore
{
public:
// Copy control
AbstractStore(const AbstractStore& orig) : myFactory(new AbstractFactory(orig.myFactory)) {}
AbstractStore& operator=(const AbstractStore& orig) { return *this; } // TODO
~AbstractStore(void) {}
protected:
// Constructor
AbstractStore(void) {}
// Data members
AbstractFactory* myFactory;
};
class ConcreteStoreA : public AbstractStore
{
public:
ConcreteStoreA(void) { myFactory = new ConcreteFactoryA; }
~ConcreteStoreA(void) {}
};
class ConcreteStoreB : public AbstractStore
{
public:
ConcreteStoreB(void) { myFactory = new ConcreteFactoryB; }
~ConcreteStoreB(void) {}
};
Code with smart pointers:
#pragma once
#include "AbstractFactory.h"
#include <memory>
class AbstractStore
{
public:
// Copy control
AbstractStore(const AbstractStore& orig) : myFactory(orig.myFactory) {}
AbstractStore& operator=(const AbstractStore& orig) { myFactory = orig.myFactory; return *this; }
~AbstractStore(void) {}
protected:
// Constructor
AbstractStore(void) {}
// Data members
std::shared_ptr<AbstractFactory> myFactory;
};
class ConcreteStoreA : public AbstractStore
{
public:
ConcreteStoreA(void) { myFactory = std::make_shared<AbstractFactory>(ConcreteFactoryA()); }
~ConcreteStoreA(void) {}
};
class ConcreteStoreB : public AbstractStore
{
public:
ConcreteStoreB(void) { myFactory = std::make_shared<AbstractFactory>(ConcreteFactoryB()); }
~ConcreteStoreB(void) {}
};
You are not using make_shared correctly. Use:
std::make_shared<ConcreteFactory>();
You call it without any arguments here. make_shared is not accepting a constructed object but the arguments that are forwarded to it's constructor. In your case you would be forwarding to the copy constructor, which works poorly with abstract hierarchies. If you want copyable objects in hierarchies, use clone member functions with covariant return types.
This will return a shared_ptr<ConcreteFactory> which will be converted to shared_ptr<AbstractFactory> in the assignment (see (9) here. Also, use constructor initializer lists and virtual destructors.
You probably want one of these two things to make your smart pointer approach work:
Make ConcreteFactoryA and ConcreteFactoryB return a std::shared_ptr<AbstractFactory> or std::unique_ptr<AbstractFactory>. Simply assign, or better yet, initialize, in your "Store" classes
Initialize your shared_ptr<>s from raw pointers using std::shared_ptr<>::reset or the constructor
You would normally only use std::make_shared<> with smart pointers where you use new with raw pointers. In your case, you are simply assigning the pointer, so you shouldn't use it.
here is the thing, I want to (probably not the best thing to do) have the ability to call some class constructor that receives as a parameter a pointer to the class who's calling (ufff!!!). Well in code looks better, here it goes, as I do it in C#.
public class SomeClass
{
SomeOtherClass someOtherClass;
//Constructor
public SomeClass(SomeOtherClass someOtherClass)
{
this->someOtherClass = someOtherClass;
}
}
public class SomeOtherClass
{
public SomeOtherMethod()
{
SomeClass c = new SomeClass(this);
}
}
So, How can I achieve the same result in c++?
Thanx in advance.
class SomeOtherClass; // forward declaration (needed when used class is not visible)
class SomeClass
{
SomeOtherClass *someOtherClass;
public:
SomeClass(SomeOtherClass *some) : someOtherClass(some)
{} // this is called initialization at constructor (not assignment)
}
class SomeOtherClass
{
public:
SomeOtherMethod()
{
SomeClass *c = new SomeClass(this);
}
}
Having answered your requirements above, also note that in C++ you really don't need to declare objects always with new. If you declare,
SomeOtherClass someOtherClass;
then it means that you have an object of SomeOtherClass named someOtherClass.
probably not the best thing to do
It might not be a bad idea. However, every time you use pointers in C++, you must be completely clear about how it will be used: what kind of thing is being pointed to (not just the type of the pointer, but scalar vs. array, etc.), how the pointed-at thing gets there (e.g. via new? As part of some other object? Something else?), and how it will all get cleaned up.
How can I achieve the same result in c++?
Almost identically, except of course that C++ does not use new when you create a local instance by value (so we instead write SomeClass c = SomeClass(this);, or more simply SomeClass c(this);), and we must be aware of the pointer vs. value types (so SomeClass::someOtherClass is now a SomeOtherClass *, which is also the type we accept in the constructor). You should also strongly consider using initialization lists to initialize data members, thus SomeClass::SomeClass(SomeOtherClass* someOtherClass): someOtherClass(someOtherClass) {}.
You can do pretty much the same thing in C++ as well:
class B;
class A
{
public:
A (B * b) : pb (b) { }
private:
B * pb;
};
class B
{
public:
B () : a (this) { }
private:
A a;
};
The question is, do you really need that?
Maybe like this :)
class SomeOtherClass;
class SomeClass
{
private:
SomeOtherClass * someOtherClass;
public:
SomeClass(SomeOtherClass *someOtherClass)
{
someOtherClass = someOtherClass;
}
};
class SomeOtherClass
{
public:
void SomeOtherMethod()
{
SomeClass *c = new SomeClass(this);
}
};
'this' is a pointer-to-const in member functions (methods) declared as const.
So:
void f1(X* p);
void f2(const X* p);
class X {
void m1() {
f1(this); // OK
f2(this); // also OK
}
void m2() const {
f2(this); // OK
f1(this); // error, 'this' is a pointer to const X
}
};
Let's say that I have two classes A and B.
class A
{
private:
int value;
public:
A(int v)
{
value = v;
}
};
class B
{
private:
A value;
public:
B()
{
// Here's my problem
}
}
I guess it's something basic but I don't know how to call A's constructor.
Also the compiler demands a default constructor for class A. But if A has a default constructor than wouldn't the default constructor be called whenever I declare a variable of type A. Can I still call a constructor after the default constructor has been called? Or can I declare an instance of a class and then call a constructor later?
I think this could be solved using pointers but can that be avoided ?
I know that you can do something like this in C#.
EDIT: I want to do some computations in the constructor and than initialize the classes. I don't know the values beforehand.
Let's say I'm reading the value from a file and then I initialize A accordingly.
The term you are looking for is initializer list. It is separated from the constructor body with a colon and determines how the members are initialized. Always prefer initialization to assignment when possible.
class A
{
int value;
public:
A(int value) : value(value) {}
};
class B
{
A a;
public:
B(int value) : a(value) {}
}
I want to do some computations in the constructor and than initialize the classes. I don't know the values beforehand.
Simply perform the computation in a separate function which you then call in the initializer list.
class B
{
A a;
static int some_computation()
{
return 42;
}
public:
B() : a(some_computation()) {}
}
You use an initialization list to initialize the member variables.
public:
B() : value(4) { // calls A::A(4) for value.
}
Or can I declare an instance of a class and then call a constructor later?
Yes, you can do that. Instead of (A value;) declare (A* value;), and then B's constructor will be B():value(new A(5)){}.
In the B's destructor you will have to do delete value;
I think this could be solved using pointers but can that be avoided ?
Yes. Use shared_ptr.
Try:
B() :
value(0)
{
// Here's my problem
}