I want to make some "duel" with two "units".
I write class "duel" that constructs from two "units".
But some kind of "unit" is special (inherited from units) like heroes, bosses etc. And they want to use special strikes during battle.
But actually class "duel" doesn't know who is hero, or who is pure unit.
Code looks like this:
#include <iostream>
class unit{
public:
unit(){};
virtual void make_hit(){
std::cout<<"pure hit\n";
}
};
class hero:public unit {
public:
hero():unit(){};
void make_hit(){
std::cout<<"SUPER hit\n";
}
};
class duel {
unit *a, *b;
public:
duel(unit _a, unit _b):a(&_a),b(&_b){};
void start (){
a->make_hit();
b->make_hit();
}
};
int main(){
duel(unit(),hero()).start();
return 0;
}
I have two main problem.
First - I use refers to temporary objects in constructor. That objects illegal when duel::duel() finished.
Second - my hero turned into pure unit, and doesn't use "SUPER hit"
Is it possible fix it in elegant way (without changing call in main())?
Due to slicing, it's better to always use polymorphism together with
smart-pointers. This would be a possible design:
#include <iostream>
#include <memory>
#include <utility>
using namespace std;
class unit_base
{
public:
virtual ~unit_base() = default;
virtual void make_hit() =0;
};
class unit : public unit_base
{
public:
unit() = default;
virtual void make_hit() override
{
cout << "pure hit" << endl;
}
};
class hero : public unit_base
{
public:
hero() = default;
virtual void make_hit() override
{
cout << "SUPER hit" << endl;
}
};
class duel
{
public:
duel( shared_ptr<unit_base> a, shared_ptr<unit_base> b )
: a(a), b(b)
{}
void start()
{
auto aa = a.lock();
auto bb = b.lock();
if( aa && bb )
{
aa->make_hit();
bb->make_hit();
} else {
cout << "duelist expired" << endl;
}
}
private:
weak_ptr<unit_base> a, b;
};
int main()
{
// use with temporarys
duel{ make_shared<unit>(), make_shared<hero>() }.start();
cout << "-------------" << endl;
// use with variables
auto u = make_shared<unit>();
auto h = make_shared<hero>();
duel d{h,u};
d.start();
cout << "-------------" << endl;
// try to use with expired duelists
u.reset();
d.start();
}
Also remember to always have a virtual destructor in your base-class.
In
duel(unit _a, unit _b):a(&_a),b(&_b){};
You are slicing the objects as you are passing by value. To fix this you can take in pointers in your constructor
duel(unit* _a, unit* _b):a(_a),b(_b){};
And then you will need to change main() to create to objects and pass them to duel
int main(){
unit npc;
hero bob;
duel d(&npc,&bob);
d.start();
return 0;
}
The only way I have found for myself in C++ is make all combination of constructor in "duel" class. This solution not so elegant, need changing in "duel" code when added new class, and also this have overhead.
~duel(){
delete a;
delete b;
}
#define _cc(t1, t2) duel(t1 _a, t2 _b) : a(new t1 (_a)), b (new t2(_b)){}
_cc(unit,unit);
_cc(hero,unit);
_cc(unit,hero);
_cc(hero,hero);
#undef _cc
I also tried use template for this, but I can't find a way make automatic type determination.
Related
If I have a class that's inheriting from another, is it possible to replace the inherited class in the child? I've got a demo of what I'm trying to do below, but I'm not sure the syntax.
#include <iostream>
class singleNum
{
public:
int m_a;
singleNum(int a)
{
std::cout << "SETUP" << std::endl;
m_a = a;
}
~singleNum()
{
std::cout << "CLOSEDOWN" << std::endl;
}
};
class inheritor : public singleNum
{
public:
inheritor(int a) : singleNum(a) {};
reset(int b)
{
singleNum::this = *singleNum(b);
}
};
int main()
{
inheritor z(5);
std::cout << z.m_a << std::endl;
z.reset(5);
return 0;
}
No
You cannot exchange or reset the base class. If it had a reset method of it's own, you could call this, but you cannot call the constructor again.
If you want to do this, you should favor composition over inheritance. You can then create a completely new instance of the inner composition class and replace your existing instance.
Your current demo isn't hard to implement, but you'll need to modify the parent class:
#include <iostream>
class singleNum
{
public:
int m_a;
singleNum(int a)
{
std::cout << "SETUP" << std::endl;
reset(a);
}
~singleNum()
{
std::cout << "CLOSEDOWN" << std::endl;
}
virtual void reset(int b)
{
m_a = b;
}
};
class inheritor : public singleNum
{
public:
inheritor(int a) : singleNum(a) {}
void reset(int b) override
{
singleNum::reset(b);
}
};
int main()
{
inheritor z(5);
std::cout << z.m_a << std::endl;
z.reset(5);
return 0;
}
But this is the closest you will get to "replacing the base class". If your case is different than the demo presented and you need to call the base class constructor on an already constructed derived object then no, this is not doable.
I've a parent class with 2 or more child class deriving from it. The number of different child classes may increase in future as more requirements are presented, but they'll all adhere to base class scheme and will contain few unique methods of their own. Let me present an example -
#include <iostream>
#include <string>
#include <vector>
#include <memory>
class B{
private: int a; int b;
public: B(const int _a, const int _b) : a(_a), b(_b){}
virtual void tell(){ std::cout << "BASE" << std::endl; }
};
class C : public B{
std::string s;
public: C(int _a, int _b, std::string _s) : B(_a, _b), s(_s){}
void tell() override { std::cout << "CHILD C" << std::endl; }
void CFunc() {std::cout << "Can be called only from C" << std::endl;}
};
class D : public B{
double d;
public: D(int _a, int _b, double _d) : B(_a, _b), d(_d){}
void tell() override { std::cout << "CHILD D" << std::endl; }
void DFunc() {std::cout << "Can be called only from D" << std::endl;}
};
int main() {
std::vector<std::unique_ptr<B>> v;
v.push_back(std::make_unique<C>(1,2, "boom"));
v.push_back(std::make_unique<D>(1,2, 44.3));
for(auto &el: v){
el->tell();
}
return 0;
}
In the above example tell() method would work correctly since it is virtual and overrided properly in child classes. However for now I'm unable to call CFunc() method and DFunc() method of their respective classes. So I've two options in my mind -
either packup CFunc() and friends inside some already defined virtual method in child class so that it executes together. But I'll loose control over particular execution of unique methods as their number rises.
or provide some pure virtual methods in base class, which would be like void process() = 0 and let them be defined in child classes as they like. Would be probably left empty void process(){} by some and used by some. But again it doesn't feels right as I've lost return value and arguments along the way. Also like previous option, if there are more methods in some child class, this doesn't feels right way to solve.
and another -
dynamic_cast<>?. Would that be a nice option here - casting back parent's pointer to child's pointer (btw I'm using smart pointers here, so only unique/shared allowed) and then calling the required function. But how would I differentiate b/w different child classes? Another public member that might return some unique class enum value?
I'm quite unexperienced with this scenario and would like some feedback. How should I approach this problem?
I've a parent class with 2 or more child class deriving from it... But I'll loose control over particular execution of unique methods as their number rises.
Another option, useful when the number of methods is expected to increase, and the derived classes are expected to remain relatively stable, is to use the visitor pattern. The following uses boost::variant.
Say you start with your three classes:
#include <memory>
#include <iostream>
using namespace std;
using namespace boost;
class b{};
class c : public b{};
class d : public b{};
Instead of using a (smart) pointer to the base class b, you use a variant type:
using variant_t = variant<c, d>;
and variant variables:
variant_t v{c{}};
Now, if you want to handle c and d methods differently, you can use:
struct unique_visitor : public boost::static_visitor<void> {
void operator()(c c_) const { cout << "c" << endl; };
void operator()(d d_) const { cout << "d" << endl; };
};
which you would call with
apply_visitor(unique_visitor{}, v);
Note that you can also use the same mechanism to uniformly handle all types, by using a visitor that accepts the base class:
struct common_visitor : public boost::static_visitor<void> {
void operator()(b b_) const { cout << "b" << endl; };
};
apply_visitor(common_visitor{}, v);
Note that if the number of classes increases faster than the number of methods, this approach will cause maintenance problems.
Full code:
#include "boost/variant.hpp"
#include <iostream>
using namespace std;
using namespace boost;
class b{};
class c : public b{};
class d : public b{};
using variant_t = variant<c, d>;
struct unique_visitor : public boost::static_visitor<void> {
void operator()(c c_) const { cout << "c" << endl; };
void operator()(d d_) const { cout << "d" << endl; };
};
struct common_visitor : public boost::static_visitor<void> {
void operator()(b b_) const { cout << "b" << endl; };
};
int main() {
variant_t v{c{}};
apply_visitor(unique_visitor{}, v);
apply_visitor(common_visitor{}, v);
}
You can declare interfaces with pure methods for each device class. When you define a specific device implementation, you inherit only from the interfaces that make sense for it.
Using the interfaces that you define, you can then iterate and call methods which are specific to each device class.
In the following example I have declared a HardwareInterface which will be inherited by all devices, and an AlertInterface which will be inherited only by hardware devices that can physically alert a user. Other similar interfaces can be defined, such as SensorInterface, LEDInterface, etc.
#include <iostream>
#include <memory>
#include <vector>
class HardwareInteface {
public:
virtual void on() = 0;
virtual void off() = 0;
virtual char read() = 0;
virtual void write(char byte) = 0;
};
class AlertInterface {
public:
virtual void alert() = 0;
};
class Buzzer : public HardwareInteface, public AlertInterface {
public:
virtual void on();
virtual void off();
virtual char read();
virtual void write(char byte);
virtual void alert();
};
void Buzzer::on() {
std::cout << "Buzzer on!" << std::endl;
}
void Buzzer::off() {
/* TODO */
}
char Buzzer::read() {
return 0;
}
void Buzzer::write(char byte) {
/* TODO */
}
void Buzzer::alert() {
std::cout << "Buzz!" << std::endl;
}
class Vibrator : public HardwareInteface, public AlertInterface {
public:
virtual void on();
virtual void off();
virtual char read();
virtual void write(char byte);
virtual void alert();
};
void Vibrator::on() {
std::cout << "Vibrator on!" << std::endl;
}
void Vibrator::off() {
/* TODO */
}
char Vibrator::read() {
return 0;
}
void Vibrator::write(char byte) {
/* TODO */
}
void Vibrator::alert() {
std::cout << "Vibrate!" << std::endl;
}
int main(void) {
std::shared_ptr<Buzzer> buzzer = std::make_shared<Buzzer>();
std::shared_ptr<Vibrator> vibrator = std::make_shared<Vibrator>();
std::vector<std::shared_ptr<HardwareInteface>> hardware;
hardware.push_back(buzzer);
hardware.push_back(vibrator);
std::vector<std::shared_ptr<AlertInterface>> alerters;
alerters.push_back(buzzer);
alerters.push_back(vibrator);
for (auto device : hardware)
device->on();
for (auto alerter : alerters)
alerter->alert();
return 0;
}
Interfaces can be even more specific, as per individual sensor type: AccelerometerInterface, GyroscopeInterface, etc.
While what you ask is possible, it will either result in your code scattered with casts, or functions available on classes that make no sense. Both are undesirable.
If you need to know if it's a class C or D, then most likely either storing it as a B is wrong, or your interface B is wrong.
The whole point of polymorphism is that the things using B is that they don't need to know exactly what sort of B it is. To me, it sounds like you're extending classes rather than having them as members, ie "C is a B" doesn't make sense, but "C has a B does".
I would go back and reconsider what B,C,D and all future items do, and why they have these unique functions that you need to call; and look into if function overloading is what you really want to do. (Similar to Ami Tavory suggestion of visitor pattern)
you can use unique_ptr.get() to get the pointer in Unique Pointer,And the use the pointer as normall. like this:
for (auto &el : v) {
el->tell();
D* pd = dynamic_cast<D*>(el.get());
if (pd != nullptr)
{
pd->DFunc();
}
C* pc = dynamic_cast<C*>(el.get());
if (pc != nullptr)
{
pc->CFunc();
}
}
and the result is this:
CHILD C
Can be called only from C
CHILD D
Can be called only from D
You should use your 1st approach if you can to hide as much type-specific implementation details as possible.
Then, if you need public interfaces you should use virtual funtions (your 2nd approach), and avoid dynamic_cast (your 3rd approach). Many theads can tell you why (e.g. Polymorphism vs DownCasting). and you already mentioned one good reason, which is you shouldn't really check for the object type ...
If you have a problem with virtual functions because your drived classes have too many unique public interfaces, then it's not IS-A relationship and it's time to review your design. For example, for shared functionality, consider composition, rather than inheritance ...
There's been a lot of comments (in OP and Ami Tavory's answer) about visitor pattern.
I think it is and acceptable answer here (considering the OP question), even if visitor pattern has disadvantages, it also has advantages (see this topic: What are the actual advantages of the visitor pattern? What are the alternatives?). Basically, if you'll need to add a new child class later, the pattern implementation will force you to consider all cases where specific action for this new class has to be taken (compiler will force you to implement the new specific visit method for all your existing visitor child classes).
An easy implementation (without boost):
#include <iostream>
#include <string>
#include <vector>
#include <memory>
class C;
class D;
class Visitor
{
public:
virtual ~Visitor() {}
virtual void visitC( C& c ) = 0;
virtual void visitD( D& d ) = 0;
};
class B{
private: int a; int b;
public: B(const int _a, const int _b) : a(_a), b(_b){}
virtual void tell(){ std::cout << "BASE" << std::endl; }
virtual void Accept( Visitor& v ) = 0; // force child class to handle the visitor
};
class C : public B{
std::string s;
public: C(int _a, int _b, std::string _s) : B(_a, _b), s(_s){}
void tell() override { std::cout << "CHILD C" << std::endl; }
void CFunc() {std::cout << "Can be called only from C" << std::endl;}
virtual void Accept( Visitor& v ) { v.visitC( *this ); }
};
class D : public B{
double d;
public: D(int _a, int _b, double _d) : B(_a, _b), d(_d){}
void tell() override { std::cout << "CHILD D" << std::endl; }
void DFunc() {std::cout << "Can be called only from D" << std::endl;}
virtual void Accept( Visitor& v ) { v.visitD( *this ); }
};
int main() {
std::vector<std::unique_ptr<B>> v;
v.push_back(std::make_unique<C>(1,2, "boom"));
v.push_back(std::make_unique<D>(1,2, 44.3));
// declare a new visitor every time you need a child-specific operation to be done
class callFuncVisitor : public Visitor
{
public:
callFuncVisitor() {}
virtual void visitC( C& c )
{
c.CFunc();
}
virtual void visitD( D& d )
{
d.DFunc();
}
};
callFuncVisitor visitor;
for(auto &el: v){
el->Accept(visitor);
}
return 0;
}
Live demo: https://ideone.com/JshiO6
Dynamic casting is the tool of absolute last resort. It is usually used when you are trying to overcome a poorly designed library that cannot be modified safely.
The only reason to need this sort of support is when you require parent and child instances to coexist in a collection. Right? The logic of polymorphism says all specialization methods that cannot logically exist in the parent should be referenced from within methods that do logically exist in the parent.
In other words, it is perfectly fine to have child class methods that don't exist in the parent to support the implementation of a virtual method.
A task queue implementation is the quintessential example (see below)
The special methods support the primary run() method. This allows a stack of tasks to be pushed into a queue and executed, no casts, no visitors, nice clean code.
// INCOMPLETE CODE
class Task
{
public:
virtual void run()= 0;
};
class PrintTask : public Task
{
private:
void printstuff()
{
// printing magic
}
public:
void run()
{
printstuff();
}
};
class EmailTask : public Task
{
private:
void SendMail()
{
// send mail magic
}
public:
void run()
{
SendMail();
}
};
class SaveTask : public Task
private:
void SaveStuff()
{
// save stuff magic
}
public:
void run()
{
SaveStuff();
}
};
Here's a "less bad" way of doing it, while keeping it simple.
Key points:
We avoid losing type information during the push_back()
New derived classes can be added easily.
Memory gets deallocated as you'd expect.
It's easy to read and maintain, arguably.
struct BPtr
{
B* bPtr;
std::unique_ptr<C> cPtr;
BPtr(std::unique_ptr<C>& p) : cPtr(p), bPtr(cPtr.get())
{ }
std::unique_ptr<D> dPtr;
BPtr(std::unique_ptr<D>& p) : dPtr(p), bPtr(dPtr.get())
{ }
};
int main()
{
std::vector<BPtr> v;
v.push_back(BPtr(std::make_unique<C>(1,2, "boom")));
v.push_back(BPtr(std::make_unique<D>(1,2, 44.3)));
for(auto &el: v){
el.bPtr->tell();
if(el.cPtr) {
el.cPtr->CFunc();
}
if(el.dPtr) {
el.dPtr->DFunc();
}
}
return 0;
}
I have multiple classes that need to share a single instance of another class. Publicly it should be unknown that this class exists. Is it appropriate to do something like the following? (Was tested as written)
#include <iostream>
class hideme
{
private:
int a;
public:
void set(int b) { a = b; }
void add(int b) { a += b; }
int get() { return a; }
hideme() : a(0) { }
};
class HiddenWrapper
{
protected:
static hideme A;
};
hideme HiddenWrapper::A;
class addOne : public HiddenWrapper
{
public:
void add() { A.add(1); }
int get() { return A.get(); }
};
class addTwo : public HiddenWrapper
{
public:
void add() { A.add(2); }
int get() { return A.get(); }
};
int main()
{
addOne a;
addTwo b;
std::cout << "Initialized: " << a.get() << std::endl;
a.add();
std::cout << "Added one: " << a.get() << std::endl;
b.add();
std::cout << "Added two: " << b.get() << std::endl;
return 0;
}
For what it's worth, hideme is part of a library I'm attempting to design a facade around, and the other classes have members from the library that interact with the static hideme.
Additionally, if the header file written for HiddenWrapper has no corresponding source file, is that the best place to define its static member? With an include guard.
Is there any other method to solve this problem? As far as I could imagine (not terribly far) I could only solve it otherwise with friendship, which I am wary of.
You can prevent access to a class by not making it accessible outside the translation unit that uses it.
// public_header.h
class A {
void bar();
};
class B {
void foo();
}
// private_implementation.cpp
#include "public_header.h"
namespace {
class hidden { void baz() {} };
hidden h;
}
void A::bar() {
h.baz();
}
void B::foo() {
h.baz();
}
This class will be usable only by A::bar and B::foo. The type hidden and the variable h still technically have external linkage, but no other translation unit can say their names.
Sometimes it is a better idea to inject shared ressources (by reference or pointer) through the constructor (also known as composition instead of inheritance). This way gives you the ability to share or not (e.g. to have a thread-safe variant of your code which is not). See http://de.wikipedia.org/wiki/Inversion_of_Control principle for more info.
This implements a singleton around some other class and hides it from
users:
class hideme {};
// fwd declarations
class x;
// library internal
class S
{
S() = delete;
S(S const&) = delete;
void operator=(S const&) = delete;
private:
static hideme& getInstance()
{
static hideme instance;
return instance;
}
friend x;
};
// library classes
class x {
hideme& s;
public:
x() : s(S::getInstance()) {}
};
int main()
{
x x;
return 0;
}
This does not handle cases where you actually want the hideme
instance to be destroyed when no other object is using it anymore. For
that you need to get a little bit more inventive using reference
counting.
I also should say that I think this is a bad idea. Singletons almost
always are.
Generally, the best approach, if you have a variable in the main part, and want to share it with all classes.
For example, if class X makes a change on this var, the change happened to the var in the main as well: you can use EXTEND
************************ The main *********************
#include <iostream>
using namespace std;
#include "Game.hpp"
//0: not specified yet; 1:singlemode; 2:multiplayerMode
int playingMode = 0;
int main()
{
Game game;
game.Run();
std::cout<< playingMode << std::endl;
return 0;
}
*********************** Class X *****************
#include <iostream>
using namespace std;
extern int playingMode;
....
....
if(m_isSinglePressed)
{
playingMode = 1;
...
}
else if(m_isMultiPressed)
{
playingMode = 2;
...
}
I am having a weird problem, which I'm sure has an easy fix. I have a super class let's call it "Bird". Bird has a virtual function called chirp, which returns me 0. I also have a subclass lets call it...SomeOtherBird. SomeOtherBird is a subclass of Bird. The chirp() function for my subclass is supposed to return me 1.
So far:
Bird.Chirp() should return 0
SomeOtherBird.Chirp() should return 1
Some other bird is a subclass of bird.
Now assuming I pass in Bird into a seperate constructor, let's call it nest.
So: nest(Bird& x)
if I pass a SomeOtherBird in, and I call Chirp, it calls the virtual function of the main super-class and not of the subclass, so for example:
SomeOtherBird x;
Nest(x);
and then if I do x.chirp, the main method is called, not the one of the subclass.
How do I get the function in the sub-class to be called, and not the virtual main function?
Thanks
I worked for me.
ideone.com/RRfau
You really ought to include some example code with questions like this so we can help you.
#include <iostream>
#include <typeinfo>
class Bird
{
public:
virtual ~Bird() {}
virtual int chirp() { return 0; }
};
class SomeOtherBird : public Bird
{
public:
virtual int chirp() { return 1; }
};
void nest( Bird& x )
{
std::cout << typeid(x).name() << " says " << x.chirp() << '\n';
}
int main()
{
SomeOtherBird s;
nest( s );
Bird b;
nest( b );
}
Works fine as shown below. Perhaps you might not have made the base method virtual. Or there is something else wrong in the code, since the code was not posted, it is impossible to tell.
#include <iostream>
using namespace std;
class Bird
{
public:
Bird() {}
~Bird() {}
virtual int Chrip() { cout << "Bird version" << endl; return 0; }
};
class SomeOtherBird:public Bird
{
public:
SomeOtherBird() {}
~SomeOtherBird() {}
virtual int Chrip() { cout << "SomeOtherBird version" << endl; return 1; }
};
int nest(Bird &b)
{
b.Chrip();
}
int main()
{
SomeOtherBird s;
Bird &b = s;
int retcode = nest(b);
cout << "retcode " << retcode << endl;
}
Output:
rhdevblade1-~/cpp: ./virt
SomeOtherBird version
retcode 1
Without seeing your code it's impossible to answer you for sure. However, this sounds like you did not write "virtual Bird()" in your base class, only in the derived class. That doesn't work.
class Bird {
virtual int Bird();
};
class MoreBird : public Bird {
int Bird();
};
The virtual keyword is not required in the deriving class (although it is not good practice not to put it there even if 99.9% of the programmers are lazy and don't do it.)
Due to the well-known issues with calling virtual methods from inside constructors and destructors, I commonly end up with classes that need a final-setup method to be called just after their constructor, and a pre-teardown method to be called just before their destructor, like this:
MyObject * obj = new MyObject;
obj->Initialize(); // virtual method call, required after ctor for (obj) to run properly
[...]
obj->AboutToDelete(); // virtual method call, required before dtor for (obj) to clean up properly
delete obj;
This works, but it carries with it the risk that the caller will forget to call either or both of those methods at the appropriate times.
So the question is: Is there any way in C++ to get those methods to be called automatically, so the caller doesn't have to remember to do call them? (I'm guessing there isn't, but I thought I'd ask anyway just in case there is some clever way to do it)
While there is no automated way, you could force the users hand by denying users access to the destructor on that type and declaring a special delete method. In this method you could do the virtual calls you'd like. Creation can take a similar approach which a static factory method.
class MyObject {
...
public:
static MyObject* Create() {
MyObject* pObject = new MyObject();
pObject->Initialize();
return pObject;
}
Delete() {
this->AboutToDelete();
delete this;
}
private:
MyObject() { ... }
virtual ~MyObject() { ... }
};
Now it is not possible to call "delete obj;" unless the call site has access to MyObject private members.
The best I can think of is for you to implement your own smart pointer with a static Create method that news up an instance and calls Initialize, and in its destructor calls AboutToDelete and then delete.
I used a very carefully designed Create() factory method (static member of each class) to call a constructor and initializer pair in the same order as C# initializes types. It returned a shared_ptr to an instance of the type, guaranteeing a heap allocation. It proved reliable and consistent over time.
The trick: I generated my C++ class declarations from XML...
Except for JavedPar's idea for the pre-destruction method, there is no pre-made solution to easily do two-phase construction/destruction in C++. The most obvious way to do this is to follow the Most Common Answer To Problems In C++: "Add another layer of indirection."
You can wrap objects of this class hierarchy within another object. That object's constructors/destructor could then call these methods. Look into Couplien's letter-envelop idiom, for example, or use the smart pointer approach already suggested.
http://www.research.att.com/~bs/wrapper.pdf This paper from Stroustrup will solve your problem.
I tested this under VS 2008 and on UBUNTU against g++ compiler. It worked fine.
#include <iostream>
using namespace std;
template<class T>
class Wrap
{
typedef int (T::*Method)();
T* p;
Method _m;
public:
Wrap(T*pp, Method m): p(pp), _m(m) { (p->*_m)(); }
~Wrap() { delete p; }
};
class X
{
public:
typedef int (*Method)();
virtual int suffix()
{
cout << "X::suffix\n";
return 1;
}
virtual void prefix()
{
cout << "X::prefix\n";
}
X() { cout << "X created\n"; }
virtual ~X() { prefix(); cout << "X destroyed\n"; }
};
class Y : public X
{
public:
Y() : X() { cout << "Y created\n"; }
~Y() { prefix(); cout << "Y destroyed\n"; }
void prefix()
{
cout << "Y::prefix\n";
}
int suffix()
{
cout << "Y::suffix\n";
return 1;
}
};
int main()
{
Wrap<X> xx(new X, &X::suffix);
Wrap<X>yy(new Y, &X::suffix);
}
I was stuck with the same problem, and after a bit of research, I believe there is not any standard solution.
The suggestions that I liked most are the ones provided in the Aleksandrescu et al. book "C++ coding standards" in the item 49.
Quoting them (fair use), you have several options:
Just document it that you need a second method, as you did.
Have another internal state (a boolean) that flags if post-construction has taken place
Use virtual class semantics, in the sense that the constructor of the most-derived class decides which base class to use
Use a factory function.
See his book for details.
You can use static function template in the class. With private ctor/dtor.
Run on vs2015 community
class A {
protected:
A() {}
virtual ~A() {}
virtual void onNew() = 0;
virtual void onDelete() = 0;
public:
void destroy() {
onDelete();
delete this;
}
template <class T> static T* create() {
static_assert(std::is_base_of<A, T>::value, "T must be a descendant of A");
T* t = new T();
t->onNew();
return t;
}
};
class B: public A {
friend A;
protected:
B() {}
virtual ~B() {}
virtual void onNew() override {
}
virtual void onDelete() override {
}
};
int main() {
B* b;
b = A::create<B>();
b->destroy();
}
The main problem with adding post-constructors to C++ is that nobody has yet established how to deal with post-post-constructors, post-post-post-constructors, etc.
The underlying theory is that objects have invariants. This invariant is established by the constructor. Once it has been established, methods of that class can be called. With the introduction of designs that would require post-constructors, you are introducing situations in which class invariants do not become established once the constructor has run. Therefore, it would be equally unsafe to allow calls to virtual functions from post-constructors, and you immediately lose the one apparent benefit they seemed to have.
As your example shows (probably without you realizing), they're not needed:
MyObject * obj = new MyObject;
obj->Initialize(); // virtual method call, required after ctor for (obj) to run properly
obj->AboutToDelete(); // virtual method call, required before dtor for (obj) to clean up properly
delete obj;
Let's show why these methods are not needed. These two calls can invoke virtual functions from MyObject or one of its bases. However, MyObject::MyObject() can safely call those functions too. There is nothing that happens after MyObject::MyObject() returns which would make obj->Initialize() safe. So either obj->Initialize() is wrong or its call can be moved to MyObject::MyObject(). The same logic applies in reverse to obj->AboutToDelete(). The most derived destructor will run first and it can still call all virtual functions, including AboutToDelete().
I had the same problem for construction. This is my solution using C++14.
The idea is to declare an instance of the class Call in the same (or quite close) scope than the declaration of the final object, letting the destructor call the post-creation script.
# include <iostream>
# include <cassert>
# include <memory>
# include <typeinfo>
class A;
// This non-template class stores an access to the instance
// on which a procedure must be called after construction
// The functions are defined after A in order to avoid a loop
class Call
{
protected:
A* a;
public:
Call();
virtual ~Call();
virtual void set(A& a_) = 0;
};
// In this class, the Source must be the final type created
template <typename Source>
class Call_ : public Call
{
static_assert(std::is_final<Source>::value, "");
public:
Call_() : Call() {}
virtual ~Call_() { assert(typeid(*this->a) == typeid(Source)); }
virtual void set(A& a_) { this->a = &a_; }
};
class A
{
protected:
A(Call& call) { std::cout << "Build A" << std::endl; call.set(*this); } // <----
public:
A(A const&) { std::cout << "Copy A" << std::endl; }
virtual ~A() { std::cout << "Delete A" << std::endl; }
virtual void actions_after_construction() = 0; // post-creation procedure
};
Call::Call() : a(nullptr)
{}
Call::~Call()
{
assert(this->a);
this->a->actions_after_construction();
}
class B : public A
{
protected:
B(Call& call) : A(call) { std::cout << "Build B" << std::endl; }
public:
B(B const& b) : A(b) { std::cout << "Copy B" << std::endl; }
virtual ~B() { std::cout << "Delete B" << std::endl; }
virtual void actions_after_construction() { std::cout << "actions by B" << std::endl; }
};
class C final : public B
{
private:
C(Call& call) : B(call) { std::cout << "Build C" << std::endl; }
public:
C(std::shared_ptr<Call> p_call = std::shared_ptr<Call>(new Call_<C>)) : C(*p_call) {}
C(C const& c) : B(c) { std::cout << "Copy C" << std::endl; }
virtual ~C() { std::cout << "Delete C" << std::endl; }
virtual void actions_after_construction() { std::cout << "actions by C" << std::endl; }
};
class D final : public B
{
private:
D(Call& call) : B(call) { std::cout << "Build D" << std::endl; }
public:
D(std::shared_ptr<Call> p_call = std::shared_ptr<Call>(new Call_<D>)) : D(*p_call) {}
D(D const& d) : B(d) { std::cout << "Copy D" << std::endl; }
virtual ~D() { std::cout << "Delete D" << std::endl; }
virtual void actions_after_construction() { std::cout << "actions by D" << std::endl; }
};
int main()
{
{ C c; }
{ D d; }
return 0;
}
Haven't seen the answer yet, but base classes are only one way to add code in a class hierarchy. You can also create classes designed to be added to the other side of the hierarchy:
template<typename Base>
class Derived : public Base {
// You'd need C++0x to solve the forwarding problem correctly.
Derived() : Base() {
Initialize();
}
template<typename T>
Derived(T const& t): Base(t) {
Initialize();
}
//etc
private:
Initialize();
};