I have a base class that updates an extern reference, and I want to build an inherited class that would embed this reference as a member. A kind of default initialization of the reference.
I came up with the following solution:
#include<iostream>
class Statefull
{
public:
Statefull( int& ref ) : _base_ref(ref) {}
int& _base_ref;
// update the extern variable
void work() { std::cout << ++_base_ref << std::endl; }
};
class Stateless : public Statefull
{
public:
// use a temporary allocation
Stateless( int* p = new int() ) :
// we cannot initialize local members before base class:
// _dummy(), Statefull(_dummy)
// thus, initialize the base class on a ref to the temporary variable
Statefull(*p),
_tmp(p),
_dummy()
{
// redirect the ref toward the local member
this->_base_ref = _dummy;
}
int* _tmp;
int _dummy;
// do not forget to delete the temporary
~Stateless() { delete _tmp; }
};
int main()
{
int i = 0;
Statefull full(i);
full.work();
Stateless less;
less.work();
}
But the need of a temporary allocation in a default argument of the constructor seems quite ugly. Is there a more elegant way to achieve this kind of default initialization while keeping a reference in the base class constructor?
Well, the Stateless class is violating the rule of three. But I'll assume that's because this is just sample code to exhibit the real problem.
Now, to actually address the problem: it's perfectly valid to bind a reference to an uninitialized variable, as long as its value is not used before initialization actually happens.
Stateless() : Statefull(_dummy), _dummy() {}
The present solution works, but it seems there's some misunderstanding about why it works.
// redirect the ref toward the local member
this->_base_ref = _dummy;
You cannot "redirect" references. You can only bind a reference once: upon initialization. Assigning to a reference assigns to the object it refers to. In this case, this->_base_ref = _dummy is exactly the same as *_tmp = _dummy : it assigns the value of _dummy to *_tmp. _base_ref, however, still refers to *_tmp (you can test this with assert(&_base_ref == tmp)).
I think this might work:
StateLess(): Statefull(*new int) {}
~StateLess() { delete &_base_ref; }
You can't do without temporaries, but they don't have to be in the classes definitions.
Everything can be solved using some more classes
class StateForStateful
{
protected:
int state;
};
class Stateless: private StateForStateful, public Stateful // order is important
{
public:
Stateless():Stateful(this->state) {}
};
Related
I use a library that only returns references to created objects Entity& Create(int id). In my class, I need to create one of these and store it.
I had thought to use class member std::reference_wrapper<Entity> MyClass::m_Entity but the problem is, I would like to create this object in a call to a method like MyClass::InitEntity() – so I run into a compile error "no default constructor available" because m_Entity is not initialised in my constructor.
Is there any way around this, other than to change my class design? Or is this a case where using pointers would make more sense?
Is MyClass in a valid state if it doesn't have a valid reference to an Entity? If it is, then you should use a pointer. The constructor initializes the pointer to nullptr, and the InitEntity function assigns it to the address of a valid Entity object.
class MyClass
{
public:
MyClass(): _entity(nullptr) {}
void InitEntity() { _entity = &Create(123); }
void doSomethingWithEntity()
{
if (_entity) ...
}
private:
Entity *_entity;
};
If MyClass isn't in a valid state without a valid reference to an Entity, then you can use a std::reference_wrapper<Entity> and initialize it in the constructor.
class MyClass
{
public:
MyClass(): _entity(Create(123)) {}
void doSomethingWithEntity()
{
...
}
private:
std::reference_wrapper<Entity> _entity;
};
Of course which one you go with depends on how MyClass is supposed to be used. Personally, the interface for std::reference_wrapper is a little awkward for me, so I'd use a pointer in the second case as well (while still ensuring that it's always not null).
I have 3 questions about below code:
class cb
{
public:
int y_;
class iterator
{
public:
//void func() { y_ = 5; } // (1)
private:
int x_;
//cb a; // (2)
};
void funcCB() { }
};
class Human
{
public:
void func() const {
cb c; // (3)
c.funcCB();
}
// (4)
};
1- Why i can't use Outer class's member variable y_ inside Inner class as in (1)?
2- Why i can't create object from Outer class inside inner class as in(2) but i can only create pointer and reference?
3- Why if i moved the line at (3) cb c; to line at (4) i get compile error ?
You can't use outer class field because it's not like your class iterator have direct access to it. First of all why would you want to have access to that field? I would think about redesign your solution first. But as you wish here is what you could do to solve the issue. You would need to have reference to the object which is your parent
class cb
{
public:
cb(): it(*this) {} // Passing the reference to ourself for iterator object init to have access in iterator class access to y_ field.
int y_;
class iterator
{
public:
iterator(cb& ob): a(ob) {}
void func() { a.y_ = 5; }
private:
int x_;
cb& a; // Reference to parent object
};
iterator it; // Added because I don't see the point where you don't want to have that object in your cb class.
void funcCB() { }
};
I'm not sure what would you like to achieve here. It will throw incomplete type because you will want to create cb object in which you will create iterator object in which you will create cb object in which again you will create iterator so you would get infinite recursion (if I understand that correctly). When you point iterator to concrete object it will stop the cycle.
You should change in class cb funcCB to be void funcCB() const {} because otherwise in class Human it is understanded that in func() which is const function you want to call funcCB() which will not modify the object c from Human class and there is a difference between qualifiers because you don't have const function in that case. You can also delete const qualifier in Human class for func and this will also work. Error here happens when you don't change qualifiers, because it is different when you have const function in which you create some object to further use and when you have object as a class field and you call function which cannot change the state of Human class and CB class don't have equivalent of const function for funcCB.
Why i can't use Outer class's member variable y_ inside Inner class as in (1)?
Because y_ is a non-static data member of class cb, meaning we must access it on a particular cb object. But here comes the problem. The assignment statement y_ = 5; is equivalent to:
vvvv--------------->this points to an object of type iterator and not cb
this->y_ = 5;
In the above shown equivalent statement, the this pointer points to the current instance of type iterator and not cb. But since to access y_ we must use a cb type object, we get the mentioned error.
Basically y_ should be accessed on an object of type cb. For example, you can make func to have a parameter of type cb& and then access y_ as shown below:
class cb
{
public:
int y_;
class iterator
{
public:
//------------vvv------------------->pass object of type cb by reference
void func(cb& it) { it.y_ = 5; } // (1) OK NOW
//----------------------^^---------->access member y_ on object it
private:
int x_;
};
void funcCB() { }
};
Why i can't create object from Outer class inside inner class as in(2) but i can only create pointer and reference?
Because at point #2 the class cb is incomplete and so at point #2 we cannot create a non-static data member of type cb. This can be seen from complete type documentation which states:
Any of the following contexts requires type T to be complete:
declaration of a non-static class data member of type T;
This means that at point #2 we cannot have a declaration for a non-static data member of type cb but we can still have a declaration for a non-static data member of type cb& or cb* as we can have a pointer or a reference to an incomplete type like cb.
Why if i moved the line at (3) cb c; to line at (4) i get compile error ?
If you moved line #3(cb c;) to line #4, you won't get any compile time error. Demo
class Human
{
public:
void func() const {
//cb c; // (3)
//c.funcCB();
}
cb c; // (4) perfectly fine
};
Forgive me if I don't quite get this -- my C++ is a little rusty.
Regarding question (1) -- Have you tried the "this" keyword?
E.g.,:
void func() { this->y_ = 5; }
Here is an example almost identical to yours:
'this' pointer in C++
For question 2, you're asking for a recursive inclusion of an object. That's like saying, What is an Onion? It is a Peel that contains an Onion. Well, that Onion inside is also a Peel that contains an Onion, then a Peel, then an Onion, etc. Without some mechanism to halt (an Onion might be a Core, which contains nothing), the first instantiation of the Onion object would loop infinitely until all memory was used up.
As a reference, the memory can be retrieved only when needed, and not before.
For question 3, I'm taking the lazy way out to say, them's just the rules.
UPDATE:
I'm not at work now, so I had more time to do a little more research. As I've said, my C++ is a little rusty.
Essentially for Q 1, what you're attempting to do is access the members of class "cb" from class "iterator". My research indicates that, just because "iterator" is a subclass of "cb", it doesn't get any special access privileges. So you can not access "cb::y_" from "iterator" and you can not use "this->y_" either. Methods (functions) inside the class can access "y_" directly. Sub-classes can not.
Note the following which compiles successfully:
class cb {
public:
int y_;
class iterator {
public:
void func() {
cb *z = new cb();
z->y_ = 5;
} // (1)
private:
int x_;
cb *a; // (2)
};
void funcCB() { }
};
class Human
{
public:
void func() const {
cb c; // (3)
c.funcCB();
}
// (4)
cb *z;
};
This probably is not what you're attempting to accomplish, but I expect that what you want to do can not be done the way you want. Your best bet would be to implement the "iterator" as its own class distinct from "cb" and make it a "friend" class of "cb". Or maybe better yet, and simpler, just include a set of iterator methods inside the class. The methods will have full access to all of the class attributes.
Also note the pointer reference to "cb". It does not compile as a straight object instantiation in a sub-class. Again, the Onion issue.
On a side note, remember that C++ is not Pascal. It's not Java. It can do sub-classes, but as you can see, it doesn't do them very well, or at least, it doesn't do them the way other languages do them. You're better off creating every class completely distinct from every other class, other than normal inheritance. That's sort of unofficially "The C++ Way."
I have a class and the constructor accepts a parameter. For example,
class Entity
{
private:
int number_;
public:
Entity(int number):number_(number)
{
std::cout << "Entity object created";
}
}
// header
class SuperEntity
{
private:
Entity *entity_;
public:
SuperEntity(int value);
};
// source
SuperEntity::SuperEntity(int value)
{
entity_ = new Entity(value);
}
class SuperEntity has a private member Entity. Since in order to instantiate Entity you need to pass in an int to it's constructor and cannot be done the declaration file (superentity.h) because the int value needed to instantiate Entity is not available yet, is it okay to dynamically allocate Entity in SuperEntity's constructor? Is this a bad practice? Thanks.
As Dietmar remarked, use a member initializer list:
class SuperEntity
{
Entity entity_;
public:
SuperEntity( int value )
: entity_{ value }
{}
};
It is ok per the language but not necessarily the best pratice.
Use an object if you can.
Failing that, use a smart pointer instead of a raw pointer. See std::shared_ptr and std::unique_ptr.
If you must use a raw pointer, make sure to follow The Rule of Three.
It's fine to have a pointer data field for a decoupled has-a relationship. If you really want to stick to pointers then you should prefer the std::unique_ptr to raw pointer and utilize the std::make_unique function in the member initializer list of the constructor:
class SuperEntity {
private:
std::unique_ptr<Entity> entity_;
public:
SuperEntity(int value);
};
SuperEntity::SuperEntity(int value)
: entity_(std::make_unique<Entity>(value))
{}
If you want to have a classic has-a relationship abstraction, namely a data field whose lifetime is bound to owners lifetime then loose the pointer and go with the object:
class SuperEntity {
private:
Entity entity_;
public:
SuperEntity(int value);
};
SuperEntity::SuperEntity(int value)
: entity_(value)
{}
};
The entity_ object will be destroyed once the object of type SuperEntity goes out of scope.
I have derived class and base class. in the constructor of the derived class I have to use the basic constructor of the base class. Then later on I want to re-construct the base class with deiffernet base class constructor :
class A
{
public:
int a, b;
}
class B : public A
{
B() : A()
{
...
//do some calculations to calculate a and b and then
//re-construct class A with the right values.
A(a,b) <--- ????
}
}
how to I do that ?
Constructors are meant to create objects. Hence they are used once. You should create a method to do initialization and call that from constructors.
You could provide a copy and/or move assignment operations in class A.
class A
{
public:
int a, b;
// Copy assignment operator
A& operator=(const A& rhs) {
if(this == &rhs) return *this;
a = rhs.a; b = rhs.b;
return *this;
}
// ...
};
After the above you could reinitialize it using the pattern
BaseClass::operator=(BaseClass(a,b));
which, in your case is
A::operator=(A(a,b));
If your class is an aggregate, or has an implicitly defined copy constructor, you should use those (you don't have to define your own), and use the same reinitialization pattern as above.
As others already pointed out, you can only call inhereted constructors in the initialization list of your current constructor, or (in C++11) delegate to other constructors of your current class. This is the only place where you can initialize your class.
init method
In some cases it makes sense to add in init() method, which re-initializes parts of your class. This is called two-phase-initialization. You will find it in some window-managing-APIs.
It is important to note that your object is then separated into two parts: The one that is usefully initialized in the c'tor, and the other that is initialized in init(). You must (must, must must!) initialize both parts in a way that the object is in a consistent state -- in must never be in an invalid state. As a rule of thumb: If the object is created (by a c'tor), then a destructor call must always possible. Specificly: Don't leave any pointers and handles lying around with random values.
class ChildWindow : Compontent {
shared_ptr<Component> parent_; // builds the component hierarchy
Component[] children_; // child cp'nts, unknown during c'tor
size_t nchildren_; // ...use e vector in real code!
public:
ChildWindow(chared_ptr<>Component> parent)
: parent_(parent),
children(nullptr), nchildren(0) // MUST initialize
{}
void addChild(Component *child) { /*... change children_ ...*/ }
void init() {
if(nchildren > 0) { /* ...throw away old ... */ }
children_ = new Component[...];
// ... init children_ with nulls
}
};
This is only a rough idea where you may use two-phase initialization.
Wrapper
If you really just need to re-initialize everything, a technical solution might to use a simple wrapper class around you real object:
class WindowWrapper {
Window *window_;
public:
WindowWrapper() : window_(nullptr) {}
void reset() { delete window_; window_ = nullptr; }
Window& get() { return *window_; }
Window& operator*() { return get(); }
}
...typed down off-hand, probably some errors in it. This is why there already is such a wrapper in C++11:
unique_ptr<Window> win { new Window{parent, "title"} };
// ..use win...
win.reset( new Window{otherparent, "other title"} };
And if this unique_ptr is not enough you could put this inside the above wrapper.
The error
Just as a side note, To explain what the code you wrote does:
B::B() : A() {
A(a,b); // <--- ????
}
When you type line "????", you create a *temporary object of type A, which disappears on function exit. It does not call any destructor on your current object.
Why does it create a temp object? Well, you can write
A a(a,b);
as a statement and you get a new instance a of class A, constructed with the a c'tor with two arguments. This a you could use in another function call, say func(a);. But you can spare that explicit variable a by just leaving out its name:
func(A(a,b));
calls func with an unnamed ("temporary") object of class A, which disappears at the end of the statement (i.e. ;).
And these kind of temp objects you can create as an expression. And since every expression is also a statement
A(a,b);
is a valid statement -- creating a temp object, which immediately vanishes.
You cannot call the constructor of your superclass except in your initializer list. You have to use composition instead of inheritance if you want to use operations on a differrently constructed A object. If a method changes an already constructed object, it is not a contructor. So either replace the object with a newly constructed one (instead of changing it) or use non constructor methods.
Put the code to compute a and b into a method and use it in the initializer list:
class A {
public:
A(int a, int b): a_(a), b_(b) {}
};
class B : public A
{
public:
B(): A(B::computeA(), B::computeB()) {}
private:
static int computeA();
static int computeB();
};
I have made the methods static to prevent using a partially initialized object.
Although I have to say that the question and the example sound like you are using inheritance to re-use an implementation. In this case, you should not use inheritance but composition and replace the inheritance with a member object.
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.