in my program I have base GeneralHeader, MacHeader that derived from GeneralHeader and NetworkPacket with member Headers that is std list of GeneralHeader:
//Packet.h
enum HeaderType_t {General_Header_type, MAC_Header_type};
class GeneralHeader {
public:
bool Valid;
HeaderType_t HeaderType;
void PrintMe();
};
struct MACHeader: public GeneralHeader {
long unsigned DestAddr:48;
long unsigned SourceAddr:48;
void PrintMe();
};
struct Packet_t {
list<GeneralHeader> Headers;//TODO GeneralHeader
list<GeneralHeader>::iterator it_Header; //TODO GeneralHeader
void PrintMe();
};
While implementing the PrintMe() of Packet_t, that supposed to print all Headers according to HeaderType: if there is a GeneralHeader - it will use GeneralHeader.PrintMe() and if it is MACHeader in the list - it will print MACHeader.PrintMe())
I'm struggling to cast it_Header iterator from base GeneralHeader to derived MACHeader inside Packet_t method PrintMe():
//Packet.cpp
void GeneralHeader::PrintMe() {
std::cout << "Valid " << GeneralHeader::Valid << endl;
std::cout << "Header Type " << GeneralHeader::HeaderType << endl;
};
void HW_MACHeader::PrintMe() {
std::cout << "------------------------ " << endl;
std::cout << "---- MAC HEADER --- " << endl;
std::cout << "------------------------ " << endl;
GeneralHeader::PrintMe();
};
void NetworkPacket_t::PrintMe() {
std::cout << "Valid Packet " << NetworkPacket_t::ValidPacket << endl;
for (it_Header = Headers.begin(); it_Header != Headers.end(); it_Header++) {
switch (it_Header->HeaderType) {
case MAC_Header_type:
static_cast<HW_MACHeader*>(it_Header)->PrintMe();
break;
default:
std::cout << "default" << endl;
};
it_Header++;
};
};
The error: invalid static_cast from type 'std::_List_iterator' to type 'MACHeader*'
Thank you for any help.
The desired/normal polymorphic way would be:
Redefine PrintMe() to a virtual function so that cast is not necessary:
class GeneralHeader {
public:
bool Valid;
HeaderType_t HeaderType;
virtual void PrintMe();
};
class MACHeader: public GeneralHeader {
long unsigned DestAddr:48;
long unsigned SourceAddr:48;
public:
void PrintMe();
};
Also use vector of pointers to GeneralHeader:
list<GeneralHeader*>::iterator it_Header;
Then you can:
(*it_Header)->printMe();
The for loop will be simpler:
for (it_Header = Headers.begin(); it_Header != Headers.end();++it_Header)
(*it_Header)->PrintMe();
I don't know why you need the it_Header to be a member of the class? Can't it just be local to the loop?
You need to dereference it_Header to access the "underlying" object to address the compiler error :
static_cast<HW_MACHeader*>(*it_Header)->PrintMe();
Hoever, that will not solve your problem: you have a list of GeneralHeader; therefore because you want to downcast to an instance of HW_MACHeader, you need to use dynamic_cast; this has to be done either on a reference or a pointer:
dynamic_cast<HW_MACHeader&>(*it_Header).PrintMe();
The line above takes the object "referenced" by it_Header, and tells the compiler to cast it dynamically to a reference of type HW_MACHeader.
Note that dynamic_cast will return a null pointer if it cannot cast down to the type you want.
However, this is not a proper way to do this. You should follow user2672165's advice, and use virtual functions.
Related
I have classes Deck, abstract class Card and Spell and Minion which are both derived from Class. I have vector<unique_ptr<Card> > of all existing Cards and now I want to place them into Decks. I want to use void Deck::addCard(<unique_ptr<Card>) overloads for Minion and Spell.
I've tried changing the arguments and parameters to "dumb" * pointer, or just Card (which can't work, I know), references, non-references etc...
Calling addCard
Deck tmp;
for( const auto & it : mAllCards )
{
cout << typeid( *it ).name() << endl;
tmp.addCard( it );
}
addCard functions
void Deck::addCard( const unique_ptr<Card> & card )
{
cout << "basic" << endl;
}
void Deck::addCard( const unique_ptr<Minion> & minion )
{
cout << "minion" << endl;
}
void Deck::addCard( const unique_ptr<Spell> & spell )
{
cout << "spell" << endl;
}
The problem is that the Card version is called everytime, not the variants for derived types. Althrough typeid says Minion or Spell, not Card.
It doesn't work because overloads in C++ are resolved at compile time.
You should considere using a virtual print function from Card.
Something like this.
class Card {
public:
virtual void print() { std::cout << "basic" << std::endl; }
}
class Minion : public Card {
public:
void print() override { std::cout << "minion" << std::endl; }
}
class Spell : public Card {
public:
void print() override { std::cout << "spell" << std::endl; }
}
Then to use this print function you'll do this way.
void Deck::addCard(const unique_ptr<Card>& card)
{
card.print();
}
Otherwise there's always double dispatch pattern or maybe visitor pattern.
Found all this in this old post.
Here is the code:
#include <iostream>
#include <vector>
#include <array>
class Parent
{
public:
virtual void whatAmI(){std::cout << "A Parent" << std::endl;}
virtual long getValue(){std::cout << "value from Parent " << std::endl; return value;}
long value;
};
class Child : public Parent
{
public:
virtual void whatAmI(){std::cout << "A child" << std::endl;}
virtual long getValue(){std::cout << "value from Child " << std::endl; return value;}
long value;
};
class SomeClass
{
public:
Parent * parent;
};
int main()
{
Child c = Child();
SomeClass sc;
sc.parent = &c;
sc.parent->value = 10;
sc.parent->whatAmI();
std::cout << sc.parent->value << std::endl;
std::cout << sc.parent->getValue() << std::endl;
}
It returns:
A child
10
value from Child
0
I have read about object slicing, and made sure I would assign the value of 10 after the child has been sliced up. I still don't understand why the direct field access and the function call would give different results.
Thank you.
There is no slicing here - you're accessing via a pointer.
The behaviour is due to the fact that member-variable access is not polymorphic. So parent->value always refers to Parent::value, never Child::value. Whereas value (in Child::getValue) refers to Child::value.
I am attempting to use static polymorphism to create a decorator pattern.
As to why I do not use dynamic polymorphism, please see this QA. Basically, I could not dynamic_cast to each decorator so as to access some specific functionality present only in the decorators (and not in the base class A).
With static polymorphism this problem has been overcome, but now I cannot register all the et() methods from the decorators back to the base class A (as callbacks or otherwise), thus when A::et() gets called, only A::et() and Z::et() get executed. I want all of A,X,Y,Z ::et() to be executed (the order for X,Y,Z does not matter).
How can I do that using the following structure?
I can see in wikipedia that CRTP should allow you to access member of a derived class using static_cast, but how do you approach the problem when there are multiple derived template classes?
If this is not possible with static polymorphism but it is possible with dynamic polymorphism could you reply to the other question?
struct I {
virtual void et() = 0;
};
class A : public I {
public:
A() {
cout << "A::ctor " ;
decList.clear();
}
void regDecorator(I * decorator)
{
if (decorator) {
cout << "reg= " << decorator << " ";
decList.push_back(decorator);
}
else
cout << "dec is null!" <<endl;
}
virtual void et()
{
cout << "A::et ";
cout << "declist size= " << decList.size() << endl;
list<I*>::iterator it;
for( it=decList.begin(); it != decList.end(); it++ )
static_cast<I *>(*it)->et();
}
std::list<I*> decList; //FIXME
};
template<typename Base>
class X: public Base {
public:
X(){
cout << "X::ctor ";
Base::regDecorator(this);
}
virtual void et(){
cout << "X::et" <<endl;
}
};
template<typename Base>
class Y: public Base {//public D {
public:
Y(){
cout << "Y::ctor ";
Base::regDecorator(this);
}
void et(){
cout << "Y::et" <<endl;
}
};
template<typename Base>
class Z: public Base {//public D {
public:
Z() {
cout << "Z::ctor ";
Base::regDecorator(this);
}
void et(){
cout << "Z::et" <<endl;
}
};
int main(void) {
Z<Y<X<A> > > mlka;
cout << endl;
mlka.et();
return 0;
}
This structure is to be used as a reference for data acquisition from a set of sensors. class A is the base class and contains common functionality of all the sensors. This includes:
- data container (f.e. `boost::circular_buffer`) to hold an amount of timestamped sample data acquired from the sensor.
- a Timer used to measure some timed quantities related to the sensors.
- other common data and calculation methods (fe. `calculateMean()`, `calculateStdDeviation()`)
In fact the A::timer will call A::et() on completion in order to perform some statistical calculations on the sampled data.
Similarly, X,Y,Z are types of sensor objects each with responsibility to extract different type of information from the sampled data. and X,Y,Z::et() perform a different type of statistical calculation on the data. The aim is perform this calculation as soon as the A::Timer waiting time elapses. This is why I want to have access to all of X,Y,Z::et() from A::et(). Is it possible without affecting the static polymorphism shown in the example?
Thank you
You started using mixins, so use them to the end.
It follows a minimal, working example:
#include<iostream>
struct I {
virtual void et() = 0;
};
template<typename... T>
struct S: I, private T... {
S(): T{}... {}
void et() override {
int arr[] = { (T::et(), 0)..., 0 };
(void)arr;
std::cout << "S" << std::endl;
}
};
struct A {
void et() {
std::cout << "A" << std::endl;
}
};
struct B {
void et() {
std::cout << "B" << std::endl;
}
};
int main() {
I *ptr = new S<A,B>{};
ptr->et();
delete ptr;
}
As in the original code, there is an interface I that offers the virtual methods to be called.
S implements that interface and erases a bunch of types passed as a parameter pack.
Whenever you invoke et on a specialization of S, it invokes the same method on each type used to specialize it.
I guess the example is quite clear and can serve as a good base for the final code.
If I've understood correctly the real problem, this could be a suitable design for your classes.
EDIT
I'm trying to reply to some comments to this answer that ask for more details.
A specialization of S is all the (sub)objects with which it is built.
In the example above, S<A, B> is both an A and a B.
This means that S can extend one or more classes to provide common data and can be used as in the following example to push around those data and the other subobjects:
#include<iostream>
struct I {
virtual void et() = 0;
};
struct Data {
int foo;
double bar;
};
template<typename... T>
struct S: I, Data, private T... {
S(): Data{}, T{}... {}
void et() override {
int arr[] = { (T::et(*this), 0)..., 0 };
(void)arr;
std::cout << "S" << std::endl;
}
};
struct A {
void et(Data &) {
std::cout << "A" << std::endl;
}
};
struct B {
void et(A &) {
std::cout << "B" << std::endl;
}
};
int main() {
I *ptr = new S<A,B>{};
ptr->et();
delete ptr;
}
Consider the following code:
#include <iostream>
#include <map>
class Value
{
public:
void set(const int intValue){ intValue_ = intValue; }
int read() const { return intValue_; }
void replaceIfInMap(){
std::map<int,int>::iterator it;
it = valuesToReplace_->find(intValue_);
if(it != valuesToReplace_->end()){
intValue_ = it->second;
}
}
Value(std::map<int,int>* valuesToReplace) : valuesToReplace_(valuesToReplace){}
private:
std::map<int,int>* valuesToReplace_;
int intValue_;
};
class Holder {
public:
void doStuffWithValues(){
Value a(&valuesToReplace_), b(&valuesToReplace_), c(&valuesToReplace_);
a.set(1); b.set(2); c.set(3);
valuesToReplace[2]=5;
a.replaceIfInMap(); b.replaceIfInMap(); c.replaceIfInMap();
std::cout << "a: " << a.read()
<< " b: " << b.read()
<< " c: " << c.read() << std::endl;
}
private:
std::map<int,int> valuesToReplace_;
};
int main()
{
Holder holder;
holder.doStuffWithValues();
}
How could I get access to the valuesToReplace_ member in a more convenient (and preferably more elegant) way? I have considered storing the map as a public static member of the class Value, but that would deny the possibility of having multiple instances of the Holder class, as each Holder instance requires a set of Value instances with different replacement settings.
A global map would be an even uglier "solution"...
Calling Value::read() from Holder and doing the map interaction there is not an option as this code is only a simplification and in the real code the equivalent of each instance of Value can store pointers to other instances of the same class rendering the aforementioned method overly complex and bulky.
Why does the above code even work? Holder::valuesToReplace_ is private! Is this just normal C++ behaviour (as you cannot get that pointer without access to the private members of the class anyway)?
Why does the above code even work? Holder::valuesToReplace_ is
private!
It is private, so Holder::doStuffWithValues can access it because it is a member function, nothing wrong there.
Value a(&valuesToReplace_), b(&valuesToReplace_), c(&valuesToReplace_);
a.set(1); b.set(2); c.set(3);
Here, all your Value objects have valuesToReplace_ pointing to the same map is that what you want? It seems strange, I would either have a static map (which would make a copy on assignment) or a smart pointer to prevent unexpected deletion (but allow NULL values).
How could I get access to the valuesToReplace_ member in a more
convenient (and preferably more elegant) way?
You could keep it private and have public member functions which return begin/end const_iterators for the map, or setIntForInt/getIntForInt accessor methods which are not dependent on internal implementation.
How about passing a reference to the valuesToReplace map to your replaceIfInMap method?
class Value
{
public:
void set(const int intValue){ intValue_ = intValue; }
int read() const { return intValue_; }
void replaceIfInMap(std::map<int,int> const& valuesToReplace_){
std::map<int,int>::const_iterator it;
it = valuesToReplace_->find(intValue_);
if(it != valuesToReplace_->end()){
intValue_ = it->second;
}
}
Value() {}
private:
int intValue_;
};
class Holder {
public:
void doStuffWithValues(){
Value a, b, c;
a.set(1); b.set(2); c.set(3);
valuesToReplace_[2]=5;
a.replaceIfInMap(valuesToReplace_);
b.replaceIfInMap(valuesToReplace_);
c.replaceIfInMap(valuesToReplace_);
std::cout << "a: " << a.read()
<< " b: " << b.read()
<< " c: " << c.read() << std::endl;
}
private:
std::map<int,int> valuesToReplace_;
};
I have a complex code base at work, and i created a small example to mimic the problem and here is the below code.
< Code below for reference> - This code is compilable if we have boost libraries and FastDelegate.h linked with the project. Please let me know if you need the full compilable example project, i can email you.
I have two problems and need help resolving them.
As seen below in the code, i have a class with argument type as template for another classes object. Now when i initialize the class below in UserClass's constructor (Line 107) i get error because mBaseAcceptor is a class with template argument of type base Class, but i need to do mbaseAcceptor(new derivedAcceptor_t). Casting problem how to fix this?
Error here is
./boost/smart_ptr/shared_ptr.hpp:387:9: error: comparison between distinct pointer types ‘Acceptor<DerivedClass>*’ and ‘Acceptor<BaseClass>*’ lacks a cast
Another problem is in line 108, even if i magically say resolve this by using another acceptor of derived class, this is where i use that mDerivedAcceptor, in Line 108 i do
mDerivedAcceptor->SetDelegate(fastdelegate::MakeDelegate(this, &UserClass::HandleDelegate));
then i get error saying
"error no matching function call for HandleDelegate(DerivedClass&, bool).
This make sense because HandleDelegate has argument of type BaseClass and by storing a delegate(which is a func. ptr) we have to call the function with appropriate argument. But how to fix this.
If i cast Handler inside Acceptor class with derived class will it work when i only pass the baseClass pointer?
Code
/*
* smart_pointer_1.cpp
*
* Created on: Jul 26, 2011
* Author: balaji
*/
#include <algorithm>
#include <boost/foreach.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include "FastDelegate.h"
#include <iostream>
using namespace std;
template <class Handler>
class Acceptor {
public:
typedef fastdelegate::FastDelegate1<Handler &, bool> delegate_t;
Acceptor ();
void Initialize(Handler *&handle);
void SetDelegate(delegate_t delegate) { mDelegate = delegate; }
private:
int mValues[2];
delegate_t mDelegate;
};
template <class Handler>
Acceptor<Handler>::Acceptor()
{
std::cout << "In Constructor: " << __FUNCTION__ << std::endl;
mValues[0] = 1;
mValues[1] = 2;
}
template <class Handler>
void Acceptor<Handler>::Initialize(Handler *&handle){
if (!handle) {
std::cout << __FUNCTION__ << " : created" << std::endl;
handle = new Handler();
} else {
std::cout << __FUNCTION__ << " : Error exception" << std::endl;
}
if (mDelegate && mDelegate(*handle)) {
std::cout << "Ok Called Handle in " << __FUNCTION__ << std::endl;
} else {
std::cout << "Not Called Handle in " << __FUNCTION__ << std::endl;
}
handle->displayComputer();
}
class BaseClass {
std::string mComputer;
public:
BaseClass() {
std::cout << "In Base Constructor: " << __FUNCTION__ << std::endl;
mComputer = "Mac";
}
virtual void displayComputer() {
std::cout << "Computer type is " << mComputer << std::endl;
}
};
class DerivedClass : public BaseClass {
std::string mLanguage;
public:
DerivedClass() {
std::cout << "In Derived Constructor: " << __FUNCTION__ << std::endl;
mLanguage = "C++";
}
void displayComputer() {
std::cout << "Language is " << mLanguage << std::endl;
}
};
class UserClass {
public:
UserClass();
UserClass(bool);
typedef Acceptor<BaseClass> baseAcceptor_t;
typedef Acceptor<DerivedClass> derivedAcceptor_t;
typedef boost::shared_ptr<BaseClass> basePtr_t;
void CallDelegate(BaseClass&);
private:
boost::shared_ptr<baseAcceptor_t> mBaseAcceptor;
boost::shared_ptr<derivedAcceptor_t> mDerivedAcceptor;
BaseClass *mConnBasePtr;
bool HandleDelegate(BaseClass& baseDelegate);
};
UserClass::UserClass() : mBaseAcceptor(new baseAcceptor_t)
{
std::cout << "In Constructor: " << __FUNCTION__ << std::endl;
mBaseAcceptor->SetDelegate(fastdelegate::MakeDelegate(this, &UserClass::HandleDelegate));
mBaseAcceptor->Initialize(mConnBasePtr);
}
UserClass::UserClass(bool value)
{
std::cout << "In Constructor: " << __FUNCTION__ << std::endl;
mBaseAcceptor.reset(new derivedAcceptor_t); // <<========== Problem Here because of improper casting
mBaseAcceptor->SetDelegate(fastdelegate::MakeDelegate(this, &UserClass::HandleDelegate)); // <<=== Also here because of improper type passed to MakeDelegate function ptr. Please note HandleDelegate has an argument of type BaseClass, but Acceptor is derived class
mBaseAcceptor->Initialize(mConnBasePtr);
}
bool UserClass::HandleDelegate(BaseClass& baseDelegate)
{
std::cout << "In " << __FUNCTION__ << std::endl;
return true;
}
int main() {
std::cout << "In function: " << __FUNCTION__ << std::endl;
typedef boost::shared_ptr<UserClass> userPtr_t;
userPtr_t user(new UserClass(true));
std::cout << "In function: " << __FUNCTION__ << " at end "<< std::endl;
return 0;
}
Acceptor<DerivedClass> is not derived from Acceptor<BaseClass> (it doesn't matter that DerivedClass is derived from BaseClass or not) so the compiler can not cast one into the other.
I would get rid of the templatization of the acceptor, unless you have a good reason to keep it (which I don't see in your code) :
class Acceptor {
public:
typedef fastdelegate::FastDelegate1<BaseClass &, bool> delegate_t;
Acceptor ();
void Initialize(BaseClass *handle);
void SetDelegate(delegate_t delegate) { mDelegate = delegate; }
private:
int mValues[2];
delegate_t mDelegate;
};
void Acceptor::Initialize(BaseClass *handle){
if (!handle) {
std::cout << __FUNCTION__ << " : Error exception" << std::endl;
}
if (mDelegate && mDelegate(*handle)) {
std::cout << "Ok Called Handle in " << __FUNCTION__ << std::endl;
} else {
std::cout << "Not Called Handle in " << __FUNCTION__ << std::endl;
}
handle->displayComputer();
}
Then you don't need separate baseAcceptor_t and derivedAcceptor_t types as they both become simply Acceptor, and you can do for example :
UserClass::UserClass() : mBaseAcceptor(new Acceptor(new BaseClass))
As far as I see the only thing you loose is the ability to pass a null pointer to the acceptor's constructor and have it create its handler itself. That's a very minor loss as the real decision (instantiate a base or a derived handler) is really taken when you instantiate the Acceptor anyway (because you choose which of Acceptor<BaseClass> or Acceptor<DerivedClass> you want)
Define base class for the Acceptor template and another class that will be base to all Handler types. So your implementation will change to:
class IHandler {
};
class IAcceptor {
public:
virtual void Initialize(IHandler *) = 0;
virtual void SetDelegate(delegate_t delegate) = 0;
};
Your Acceptor template will change to:
template <class Handler>
class Acceptor : public IAcceptor {
public:
typedef fastdelegate::FastDelegate1<Handler &, bool> delegate_t;
Acceptor ();
void Initialize(IHandler *pVal);
void SetDelegate(delegate_t delegate) { mDelegate = delegate; }
private:
int mValues[2];
delegate_t mDelegate;
};
Your implementation for Initialize will change (Make sure you handle the dynamic_cast result correctly):
template <class Handler>
void Acceptor<Handler>::Initialize(IHandler *pVal){
Handler *pHandle = dynamic_cast<Handler>(pVal); //You will have to ofcourse ttake appropriate action if this cast fails.
if (!handle) {
std::cout << __FUNCTION__ << " : created" << std::endl;
handle = new Handler();
} else {
std::cout << __FUNCTION__ << " : Error exception" << std::endl;
}
if (mDelegate && mDelegate(*handle)) {
std::cout << "Ok Called Handle in " << __FUNCTION__ << std::endl;
} else {
std::cout << "Not Called Handle in " << __FUNCTION__ << std::endl;
}
handle->displayComputer();
}
Finally all classes that have to be used with the Acceptor will have to be derived from IHandler.
Now you can change your pointer declaration to shared_ptr< IAcceptor >.
EDIT:
Based on your comment for the second issue, I would pass the Handler object as a pointer instead of a reference and modify the UserClass::HandleDelegate method to accept a pointer to the BaseClass (or the IHandler class if you want to be even more generic.).
You can try to use boost::static_pointer_cast, because even though
class Derived : public Base{};
it doesn't make boost::shared<Derived> inherit from boost::shared_ptr<Base>.
So you have to use explicit boost cast like boost::static_pointer_cast, boost::dynamic_pointer_cast accordingly.