我希望能够从不同的类中调用一些成员函数,这些函数都具有相同的通用语法和基类。
的内容class A: public BaseClass
{
public:
A();
~A();
int DoFoo();
int DoBar();
int DoBarBar();
};
class B : public BaseClass
{
public:
B();
~B();
int DoSomething();
int DoSomethingElse();
int DoAnother();
};
我可能会将两个类的成员函数放在一个映射中,以便我可以使用
key value
"Option1" *DoFoo()
"Option2" *DoSomething()
"Option3" *DoFoo()
... ...
"Option6" *DoAnother()
我可以调用函数根据我选择的选项返回一个值,而不管函数属于哪个类。
通过一些搜索,我试图实现我自己的映射函数集。但是,地图保留了仿函数的地址,但其中的函数变为null。
这是我的函子声明,它存储一个类对象和一个函数指针
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
//////////////////////////////////////////////////////////////
//Functor Classes
//////////////////////////////////////////////////////////////
class TFunctor
{
public:
virtual void operator()()=0; // call using operator
virtual int Call()=0; // call using function
};
// derived template class
template <class TClass> class TSpecificFunctor : public TFunctor
{
private:
int (TClass::*fpt)(); // pointer to member function
TClass* pt2Object; // pointer to object
public:
// constructor - takes pointer to an object and pointer to a member and stores
// them in two private variables
TSpecificFunctor(TClass* _pt2Object, int(TClass::*_fpt)())
{ pt2Object = _pt2Object; fpt=_fpt; };
// override operator "()"
virtual void operator()()
{ (*pt2Object.*fpt)();}; // execute member function
// override function "Call"
virtual int Call()
{return (*pt2Object.*fpt)();}; // execute member function
};
typedef std::map<std::string, TFunctor*> TestMap;
//////////////////////////////////////////////////////////////
//Test Classes
//////////////////////////////////////////////////////////////
//Base Test class
class base
{
public:
base(int length, int width){m_length = length; m_width = width;}
virtual ~base(){}
int area(){return m_length*m_width;}
int m_length;
int m_width;
};
//Inherited class which contains two functions I would like to point to
class inherit:public base
{
public:
inherit(int length, int width, int height);
~inherit();
int volume(){return base::area()*m_height;}
int area2(){return m_width*m_height;}
int m_height;
TestMap m_map;
};
我的继承类构造函数如下所示:
inherit::inherit(int length, int width, int height):base(length, width)
{
m_height = height;
TSpecificFunctor<inherit> funcA(this, &inherit::volume);
m_map["a"] = &funcA;
TSpecificFunctor<inherit> funcB(this, &inherit::area2);
m_map["b"] = &funcB;
}
我将两个函数映射到地图中的位置。在内存地址和函数指针方面,上述函数看起来还不错。
然后我尝试在新类中创建一个inherit实例......
class overall
{
public:
overall();
~overall(){}
inherit *m_inherit;
TestMap m_mapOverall;
};
overall::overall()
{
m_inherit = new inherit(3,4,5);
TestMap tempMap = m_inherit->m_map;
int i = 0;
}
当我看到m_inherit-&gt; m_map的值时,我注意到键仍然是一致的,但是我试图指向的函数的内存地址已经消失了。
我没有太多关于仿函数的经验但是根据我的理解,它能够保留状态,我认为这意味着我可以在其类之外调用成员函数。但是我开始认为我的成员函数消失了,因为它超出了范围。
答案 0 :(得分:2)
你是对的,这是一个舀取问题。在inherit
构造函数中,funcA
和funcB
都在堆栈上分配,并在函数超出范围时销毁。叶子m_map
带有陈旧的指针。
你真正想要的是像
inherit::inherit(int lenght, int width, int height) :base(length, width)
{
m_height = height;
// allocated on the heap
TSpecificFunctor<inherit> * funcA = new TSpecificFunctor<inherit>(this, &inherit::volume);
m_map["a"] = funcA;
// allocated on the heap
TSpecificFunctor<inherit> * funcB = new TSpecificFunctor<inherit>(this, &inherit::area2);
m_map["b"] = funcB;
} // when this function exits funcA and funcB are not destroyed
但是,为了避免任何内存泄漏,inherit
的析构函数需要清理值
inherit::~inherit()
{
for(TestMap::iterator it = m_map.begin(); it != m_map.end(); ++it) {
delete it->second;
}
}
使用new
和delete
很容易导致内存泄漏。为了防止它们,我建议您研究std::unique_ptr
和std::shared_ptr
等智能点。而且,随着C ++ 11中lambda的引入,仿函数已经过时了。如果你不熟悉它们,它们真的很整洁,值得研究。
如果您的编译器支持它们,请使用lambdas
执行此操作#include <functional>
// ...
typedef std::map<std::string, std::function<int(void)>> TestMap;
// ...
inherit::inherit(int length, int width, int height):base(length, width)
{
m_height = height;
m_map["a"] = [this]() -> int { return volume(); };
m_map["b"] = [this]() -> int { return area2(); };
// can be called like so
m_map["a"]();
m_map["b"]();
}
// No need to clean up in destructors
答案 1 :(得分:1)
你是对的 - TSpecificFunctor
在inherit
的构造函数末尾超出范围,所以你不应该指向它们。
如果可以的话,更喜欢智能指针,例如
#include <memory>
...
typedef std::map<std::string, std::shared_ptr<TFunctor>> TestMap;
...
inherit::inherit(int length, int width, int height):base(length, width)
{
m_height = height;
m_map["a"] = std::shared_ptr<TSpecificFunctor<inherit>>(
new TSpecificFunctor<inherit>(this, &inherit::volume));
m_map["b"] = std::shared_ptr<TSpecificFunctor<inherit>>(
new TSpecificFunctor<inherit>(this, &inherit::area2));
}
然后,您主要担心的是确保在m_inherit->m_map
被销毁之后不会调用m_inherit
中的仿函数,否则您将获得未定义的行为。在这种情况下,你是安全的,因为你泄漏m_inherit
(它永远不会被破坏)。