【问题标题】:C++ Reactor using base & derived classes containing functional objects of different types使用包含不同类型功能对象的基类和派生类的 C++ Reactor
【发布时间】:2014-11-18 16:19:16
【问题描述】:

我创建了这个示例反应器程序来测试我想演示的功能。

基本上程序定义:

  1. 两个函数对象在不同的​​事件上被调用。

  2. 基类和派生类;其目的是允许将派生类的不同模板实例存储在同一个 stl 容器中。

  3. 一个反应器函数,它使用随机数来模拟事件,然后在容器中搜索匹配的键并调用函数对象来完成它的工作。

  4. Main 做了一些设置工作,然后调用反应器函数在不同的线程中运行。

编辑:已修改代码,使其现在可以编译和运行。抱歉,代码现在很长;它最初是一个最小的测试程序。添加了额外的部分和大量的打印语句来阐明功能。它会保留在这里以防其他人感兴趣。

#include <functional>
#include <iostream>
#include <stdlib.h>
#include <chrono>
#include <thread>
#include <unordered_map>
#include <utility>
#include <memory>

class Pollin_Functional_Object
{
public:
    //Constructor
    Pollin_Functional_Object(const int cnt) : count(cnt)
    {
        std::cout << "Pollin_Functional_Object: Constructor" << std::endl;
    }

    //Copy Constructor
    Pollin_Functional_Object(const Pollin_Functional_Object &orig) : count(orig.count)
    {
        std::cout << "Pollin_Functional_Object: Copy Constructor" << std::endl;
    }

    //Copy assignment
    Pollin_Functional_Object& operator= (const Pollin_Functional_Object &that)
    {
        std::cout << "Pollin_Functional_Object: Copy Assignment Constructor" << std::endl;      
        if (this != &that)
        {           
            count = that.count;
        }
        return *this;
    }

    //Move constructor
    Pollin_Functional_Object(Pollin_Functional_Object &&orig) /*noexcept NOT VS2013*/ : count(orig.count)
    {
        std::cout << "Pollin_Functional_Object: Move Constructor" << std::endl;     
    }

    //Move Assignment
    Pollin_Functional_Object& operator=(Pollin_Functional_Object &&that) /*noexcept NOT VS2013*/
    {
        std::cout << "Pollin_Functional_Object: Move Assignment Constructor" << std::endl;
        if (this != &that)
        {
            count = that.count;         
        }
        return *this;
    }

    //Operators
    bool operator==(const Pollin_Functional_Object &anotherPollin_Functional_Object) const
    {
        return (count == anotherPollin_Functional_Object.count);
    }

    void operator()(const int &in) //const
    {
        std::cout << "Pollin__Functional_Object: operator(" << in << ") Count: " << ++count << std::endl;       
    }

    ~Pollin_Functional_Object()
    {
        std::cout << "Pollin_Functional_Object: Destructor Called." << std::endl;
    }

private:
    int count;
};


class Pollout_Functional_Object
{
public:
    //Constructor
    Pollout_Functional_Object(const int count) : count(count)
    {
        std::cout << "Pollout_Functional_Object: Constructor" << std::endl;
    }

    //Copy Constructor
    Pollout_Functional_Object(const Pollout_Functional_Object &orig) : count(orig.count)
    {
        std::cout << "Pollout_Functional_Object: Copy Constructor" << std::endl;
    }

    //Copy assignment
    Pollout_Functional_Object& operator= (const Pollout_Functional_Object &that)
    {
        std::cout << "Pollout_Functional_Object: Copy Assignment Constructor" << std::endl;
        if (this != &that)
        {
            count = that.count;
        }
        return *this;
    }

    //Move constructor
    Pollout_Functional_Object(Pollout_Functional_Object &&orig) /*noexcept NOT VS2013*/ : count(orig.count)
    {
        std::cout << "Pollout_Functional_Object: Move Constructor" << std::endl;
    }

    //Move Assignment
    Pollout_Functional_Object& operator=(Pollout_Functional_Object &&that) /*noexcept NOT VS2013*/
    {
        std::cout << "Pollout_Functional_Object: Move Assignment Constructor" << std::endl;
        if (this != &that)
        {
            count = that.count;
        }
        return *this;
    }

    //Operators
    bool operator==(const Pollout_Functional_Object &anotherPollout_Functional_Object) const
    {
        return (count == anotherPollout_Functional_Object.count);
    }

    void operator()(const int &in) //const
    {
        std::cout << "Pollout_Functional_Object: operator(" << in << ") Count: " << ++count << std::endl;
    }

    ~Pollout_Functional_Object()
    {
        std::cout << "Pollout_Functional_Object: Destructor Called." << std::endl;
    }

private:
    int count;
};

//Needs to be non-templated base class.
class Instruction_Base
{
public:
    //Default Constructor
    Instruction_Base() = default;

    //Constructor
    Instruction_Base(const std::string &nme):name(nme)
    {
        std::cout << "Instruction_Base: Constructor" << std::endl;
    }

    //Copy Constructor
    Instruction_Base(const Instruction_Base &orig) : name(orig.name)
    {
        std::cout << "Instruction_Base: Copy Constructor" << std::endl;
    }

    //Copy assignment
    Instruction_Base& operator= (const Instruction_Base &that)
    {
        std::cout << "Instruction_Base: Copy Assignment Constructor" << std::endl;
        if (this != &that)
        {
            name = that.name;
        }
        return *this;
    }

    //Move constructor
    Instruction_Base(Instruction_Base &&orig) /*noexcept NOT VS2013*/ : name(orig.name)
    {
        std::cout << "Instruction_Base: Move Constructor" << std::endl;
    }

    //Move Assignment
    Instruction_Base& operator=(Instruction_Base &&that) /*noexcept NOT VS2013*/
    {
        std::cout << "Instruction_Base: Move Assignment Constructor" << std::endl;
        if (this != &that)
        {
            name = that.name;
        }
        return *this;
    }

    virtual ~Instruction_Base()// = default;//dynamic binding. Virtual destructor is necessary in base class even if it does no work.
    {
        std::cout << "Instruction_Base: Destructor Called" << std::endl;
    }

    //Operator
    bool operator==(const Instruction_Base &anotherInstruction_Base) const
    {
        return (name == anotherInstruction_Base.name);
    }

    virtual void callFunctionalObject(const int &in)//marked virtual.  Is overridden in derived class Instruction.
    {
        std::cout << "Instruction_Base: callFunctionalObject(" << in << ")" << std::endl;
    }

private:
    std::string name;
};

//Derived class; templated.  Will store functional-objects of different specified types.
template<typename Functional_Object>
class Instruction : public Instruction_Base //inherits from
{
public:
    //Default Constructor
    Instruction() = default;

    //Constructor
    Instruction(const std::string &nme, const std::shared_ptr<Functional_Object> &funcObj) : fo(funcObj)
    {
        std::cout << "Instruction: Constructor" << std::endl;
    }

    //Copy Constructor
    Instruction(const Instruction &orig) : Instruction_Base(orig), fo(orig.fo)
    {
        std::cout << "Instruction: Copy Constructor" << std::endl;
    }

    //Copy assignment
    Instruction& operator= (const Instruction &that)
    {
        std::cout << "Instruction: Copy Assignment Constructor" << std::endl;
        Instruction_Base::operator=(that);
        if (this != &that)
        {
            fo = that.fo;
        }
        return *this;
    }

    //Move constructor
    Instruction(Instruction &&orig) /*noexcept NOT VS2013*/ : Instruction_Base(std::move(orig)), fo(orig.fo)
    {
        std::cout << "Instruction: Move Constructor" << std::endl;
    }

    //Move Assignment
    Instruction& operator=(Instruction &&that) /*noexcept NOT VS2013*/
    {
        std::cout << "Instruction: Move Assignment Constructor" << std::endl;
        Instruction_Base::operator=(that);
        if (this != &that)
        {
            fo = that.fo;
        }
        return *this;
    }

    //Destructor
    ~Instruction()
    {
        std::cout << "Instruction: Destructor Called" << std::endl;
    }

    //Operators
    bool operator==(const Instruction_Base &anotherInstruction) const
    {
        return (name == anotherInstruction.name &&
            fo == anotherInstruction.fo);
    }

    void callFunctionalObject(const int &in) override
    {
        //std::cout << "Instruction: callFunctionalObject(" << in << ")" << std::endl;
        (*fo)(in);
    }

private:
    std::shared_ptr<Functional_Object> fo;
};

class InstructionsStore
{
public: InstructionsStore()
        {
        std::cout << "InstructionsStore: Constructor" << std::endl;
        }

        //Copy Constructor
        InstructionsStore(const InstructionsStore &orig) : instructions(orig.instructions)
        {
            std::cout << "InstructionsStore: Copy Constructor" << std::endl;
        }

        //Copy assignment
        InstructionsStore& operator= (const InstructionsStore &that)
        {
            std::cout << "InstructionsStore: Copy Assignment Constructor" << std::endl;
            if (this != &that)
            {
                instructions = that.instructions;               
            }
            return *this;
        }

        //Move constructor
        InstructionsStore(InstructionsStore &&orig) /*noexcept NOT VS2013*/ : instructions(orig.instructions)
        {
            std::cout << "InstructionsStore: Move Constructor" << std::endl;
        }

        //Move Assignment
        InstructionsStore& operator=(InstructionsStore &&that) /*noexcept NOT VS2013*/
        {
            std::cout << "InstructionsStore: Move Assignment Constructor" << std::endl;
            if (this != &that)
            {
                instructions = that.instructions;               
            }
            return *this;
        }

        //Operators
        bool operator==(const InstructionsStore &anotherInstructionsStore) const
        {
            return (instructions == anotherInstructionsStore.instructions);
        }

//Setter
    void addInstruction(const std::string nme, const std::shared_ptr<Instruction_Base> &ib)
    {
            instructions.insert(std::pair<std::string, std::shared_ptr<Instruction_Base>>(nme, ib));
    }

//Getter
    std::shared_ptr<Instruction_Base> getInstruction(const std::string nme)//returns pointer to derived Instruction type object
    {
        auto got = instructions.find(nme);
        if (got != instructions.end())
        {
            //std::cout << "InstructionsStore: getInstruction(" << (got->first).c_str() << ")" << std::endl;
            return got->second;
        }       
    }

private:
    //Specifying std::shared_ptr<Instruction_Base> base class also allows storage of pointers to types derived
    //from Instruction_Base i.e. templated Instruction class objects storing functional-objects of different types.
    //Pointers only though, does not work with actual objects.
    std::unordered_map<std::string, std::shared_ptr<Instruction_Base>> instructions;
};

//Reactor Function
void reactor(const int &iterations, const std::shared_ptr<InstructionsStore> &is)
{
//Prepare variables
int runLoop(0);
int number(0);
std::string searchFor("");
srand(time(NULL));

while (runLoop < iterations)
 {
  number = rand() % 100 + 1;//in the range 1 to 100

  if (number >= 50)
  {
      searchFor = "pollin";
  }
  else
  { 
      searchFor = "pollout";
  }

  //Find the relevant object
  std::shared_ptr<Instruction_Base> ib = is->getInstruction(searchFor);

  //Call the functional-object; passes the call via
  //the virtual function & dynamic binding in the base class Instruction_Base to
  //the overridden derived Instruction class member function.
  ib->callFunctionalObject(number);

  std::this_thread::sleep_for(std::chrono::milliseconds(1000));
  ++runLoop;
 }
}


int main(int argc, char* argv[])
{
    //Instantiate the functional-objects and corresponding shared pointers.
    std::shared_ptr <Pollin_Functional_Object> spPifo (new Pollin_Functional_Object(0));
    std::shared_ptr <Pollout_Functional_Object> spPofo(new Pollout_Functional_Object(0));

    //Instantiate the Instruction objects and corresponding shared pointers.
    std::shared_ptr <Instruction<Pollin_Functional_Object>> spPiInstr (new Instruction<Pollin_Functional_Object>("pollin", spPifo));
    std::shared_ptr <Instruction<Pollout_Functional_Object>> spPoInstr (new Instruction<Pollout_Functional_Object>("pollout", spPofo));

    //Instantiate the InstructionsStore object and corresponding shared pointer.
    std::shared_ptr<InstructionsStore> spIs(new InstructionsStore);
    spIs->addInstruction("pollin", spPiInstr);//add the instruction to the store
    spIs->addInstruction("pollout", spPoInstr);//add the instruction to the store

    //Then pass the InstructionsStore shared pointer to the reactor function and run.
    std::thread t1(reactor, 10, std::cref(spIs));
    t1.join();//wait for it.....    
    return 0;
}

【问题讨论】:

  • 什么错误?有什么问题?
  • @IdeaHat 第一个编译错误涉及:错误 LNK2001:无法解析的外部符号“public: virtual void __thiscall Instruction_Base::callFunctionalObject(int const &)” (?callFunctionalObject@Instruction_Base@@UAEXABH@Z) 可以一旦解决了,就成为其他人!
  • 所有内容实际上都定义在程序的同一个文件中吗?
  • 是的,都定义在一个文件中。

标签: c++ templates functor generic-programming reactor


【解决方案1】:

当我尝试编译这个 (g++ --std=c++11 reactor.cpp -pthread) 时,我有点神秘

/usr/include/c++/4.9/functional:1665:61: error: no type named ‘type’ in ‘class std::result_of<void (*(int, InstructionsStore))(const int&, InstructionsStore&)>’

这似乎是尝试将堆栈引用传递给线程构造函数的结果。根据定义,这些值将被复制到线程对象中,然后传递给 reactor() 函数。您需要允许复制这些对象,或者动态分配对象并传递指针。

来自http://en.cppreference.com/w/cpp/thread/thread/thread

线程函数的参数是按值复制的。如果一个 引用参数需要传递给线程函数,它有 被包装(例如使用 std::ref 或 std::cref)。

请记住,如果您使用 std::ref,您仍在将此数据传递给另一个线程,因此只有当您知道您传递给另一个线程的对象将在整个生命周期内保持活动状态时才会起作用新线程。

如果我取出反应器参数中的引用,这对我来说编译得很好(未定义您的 callFunctionalObject 函数之一的链接器错误)。

【讨论】:

  • 感谢您的浏览。我现在有了要编译的代码(VS2013),并为所有类添加了复制、复制分配、移动和移动分配代码(编辑过的原始问题)。现在的问题是程序运行但没有显示正在调用功能对象。它只是在旋转而不是参与!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多