gpt4 book ai didi

c++ - 映射仿函数到成员函数丢失范围

转载 作者:搜寻专家 更新时间:2023-10-31 01:53:15 25 4
gpt4 key购买 nike

我希望能够从具有相同通用语法和基类的不同类中调用一些成员函数。类似的东西

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()

无论函数属于哪个类,我都可以根据我选择的选项调用函数返回值。

通过一些搜索,我尝试实现我自己映射的仿函数集。然而,映射保留了仿函数的地址,但其中的函数变为空。

这是我的仿函数声明,它存储了一个类对象和一个函数指针

    #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;
}

这是我将两个函数映射到一个映射中的地方。就内存地址和函数指针而言,上述函数看起来还不错。

然后我尝试在新类中创建一个继承实例...

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->m_map 的值时,我注意到键仍然是一致的,但是我试图指向的函数的内存地址已经消失了。

我对仿函数没有太多经验,但据我了解,它能够保留状态,我认为这意味着我可以在其类之外调用成员函数。但我开始认为我的成员函数消失了,因为它超出了范围。

最佳答案

你是对的,这是一个挖矿问题。在 inherit 构造函数中,funcAfuncB 都分配在堆栈上,一旦函数超出范围就会销毁。留下带有陈旧指针的 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;
}
}

使用newdelete很容易导致内存泄漏。为了防止它们,我建议研究像 std::unique_ptrstd::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

关于c++ - 映射仿函数到成员函数丢失范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11423582/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com