ফাংশন পয়েন্টারের মাধ্যমে সি ++ শ্রেণি পদ্ধতিতে কল করা


113

আমি কীভাবে ক্লাস সদস্য ফাংশনের জন্য একটি ফাংশন পয়েন্টার পেতে পারি এবং পরে কোনও নির্দিষ্ট অবজেক্টের সাথে সেই সদস্য ফাংশনটিকে কল করব? আমি লিখতে চাই:

class Dog : Animal
{
    Dog ();
    void bark ();
}


Dog* pDog = new Dog ();
BarkFunction pBark = &Dog::bark;
(*pBark) (pDog);

এছাড়াও, যদি সম্ভব হয় তবে আমি একটি পয়েন্টারের মাধ্যমে কনস্ট্রাক্টরকেও অনুরোধ করতে চাই:

NewAnimalFunction pNew = &Dog::Dog;
Animal* pAnimal = (*pNew)();    

এটি কি সম্ভব, এবং যদি তাই হয় তবে এটি করার পক্ষে পছন্দসই উপায় কী?


1
আমি এখনও 'কেন' বুঝতে পারি না যদি আপনি কোনও অবজেক্টের সদস্য ফাংশনটি কল করতে চান তবে কেবল অবজেক্টে একটি পয়েন্টারটি পাস করুন? লোকেরা যদি অভিযোগ করে যে এটি আপনাকে ক্লাসকে আরও ভালভাবে সজ্জিত করতে সক্ষম করে কেন এমন একটি ইন্টারফেস শ্রেণি তৈরি করবেন না যা সমস্ত শ্রেণীর উত্তরাধিকার সূত্রে প্রাপ্ত?
চাদ

এটি কমান্ড প্যাটার্নের মতো কিছু বাস্তবায়নে কার্যকর হতে পারে যদিও কাঁচা সদস্য পয়েন্টার মেকানিক্সকে আড়াল করার জন্য অনেকে বুস্ট :: ফাংশন ব্যবহার করেন।
সিবি বেইলি

9
কেন আপনি এই কুকুরটিকে গতিশীলভাবে বরাদ্দ করেন? এরপরে আপনাকে নিজে নিজেও অবজেক্টটি মুছতে হবে। এটিকে দেখতে অনেকটা দেখে মনে হচ্ছে আপনি জাভা, সি # বা অন্য কোনও তুলনামূলক ভাষা থেকে এসেছেন এবং এখনও সি ++ এর সাথে লড়াই করছেন। একটি সরল স্বয়ংক্রিয় বস্তু ( Dog dog;) সম্ভবত আপনি যা চান তা সম্ভবত।
এসবিআই

1
@ চাদ: আমি বেশিরভাগ ক্ষেত্রে একমত হব তবে এমন সময় আছে যেখানে রেফারেন্স পাস করা আরও ব্যয়বহুল। একটি লুপটি বিবেচনা করুন যা কিছু প্রকারের ডেটা (পার্সিং, গণনা, ইত্যাদি ..) এর উপর পুনরাবৃত্তি করছে তার চেয়ে কিছু অংশের উপর ভিত্তি করে কোনও ফাংশন কল করতে সক্ষম হলে / অন্য গণনাগুলি এমন কোনও ব্যয় আরোপ করে যেখানে কেবল পয়েন্টকে কল করা যেমন ফাংশন এড়াতে পারে তবে / / অন্যথায় এই চেকগুলি লুপে প্রবেশের আগে করা যেতে পারে কিনা তা পরীক্ষা করে।
এরিক 18

উত্তর:


126

পড়ুন এই বিবরণের জন্য:

// 1 define a function pointer and initialize to NULL

int (TMyClass::*pt2ConstMember)(float, char, char) const = NULL;

// C++

class TMyClass
{
public:
   int DoIt(float a, char b, char c){ cout << "TMyClass::DoIt"<< endl; return a+b+c;};
   int DoMore(float a, char b, char c) const
         { cout << "TMyClass::DoMore" << endl; return a-b+c; };

   /* more of TMyClass */
};
pt2ConstMember = &TMyClass::DoIt; // note: <pt2Member> may also legally point to &DoMore

// Calling Function using Function Pointer

(*this.*pt2ConstMember)(12, 'a', 'b');

23
অবাক করে যে তারা সিদ্ধান্ত নিয়েছে যে এটি: *this.*pt2Memberকাজ করবে। *তার চেয়ে বেশি প্রাধান্য রয়েছে .*... ব্যক্তিগতভাবে, আমি এখনও লিখতে পারি this->*pt2Member, এটি অপারেটরটি কম।
অ্যালেক্সিস উইলক

7
আপনি কেন আরম্ভ pt2ConstMemberকরতে হবে NULL?
সিরো সান্তিলি 郝海东 冠状 病 六四 事件 法轮功

@ আলেকিসওয়িলকে কেন অবাক করা হচ্ছে? সরাসরি বস্তুর জন্য (পয়েন্টার নয়) এটি (object.*method_pointer)তাই আমরা *আরও বেশি অগ্রাধিকার পেতে চাই।
সিরো সান্তিলি 郝海东 冠状 病 六四 事件 法轮功

@ টোমাজাটো, যদি আমি ভুল না হয়ে থাকি (এবং আমি হতেও পারি), thisকেবল এটি প্রমাণ করতে ব্যবহার করা হচ্ছে যে আপনি যা প্রয়োগ .*করেন তা (উপ) শ্রেণীর উদাহরণের পয়েন্টার হওয়া উচিত। তবে এটি আমার কাছে নতুন বাক্য গঠন যা আমি কেবল এখানে যুক্ত অন্যান্য উত্তর এবং সংস্থানগুলির উপর ভিত্তি করে অনুমান করছি। এটিকে আরও পরিষ্কার করার জন্য আমি একটি সম্পাদনার পরামর্শ দিচ্ছি।
c1moore

1
ওহ স্ন্যাপ, 100 এ অভিনন্দন!
জোনাথন মে

57

আমি কীভাবে ক্লাস সদস্য ফাংশনের জন্য একটি ফাংশন পয়েন্টার পেতে পারি এবং পরে কোনও নির্দিষ্ট অবজেক্টের সাথে সেই সদস্য ফাংশনটিকে কল করব?

এটি দিয়ে শুরু করা সবচেয়ে সহজ typedef। সদস্য ফাংশনের জন্য, আপনি প্রকারের ঘোষণায় শ্রেণীর নাম যুক্ত করুন:

typedef void(Dog::*BarkFunction)(void);

তারপরে পদ্ধতিটি শুরু করতে আপনি ->*অপারেটরটি ব্যবহার করেন :

(pDog->*pBark)();

এছাড়াও, সম্ভব হলে আমিও পয়েন্টারের মাধ্যমে কনস্ট্রাক্টরকে অনুরোধ করতে চাই। এটি কি সম্ভব, এবং যদি তাই হয় তবে এটি করার পক্ষে পছন্দসই উপায় কী?

আমি বিশ্বাস করি না আপনি এই জাতীয় নির্মাতাদের সাথে কাজ করতে পারবেন - সিটার এবং ডটারগুলি বিশেষ। এই ধরণের জিনিস অর্জনের স্বাভাবিক উপায়টি একটি কারখানার পদ্ধতি ব্যবহার করা হবে, যা মূলত কেবল একটি স্থির ফাংশন যা আপনার জন্য কনস্ট্রাক্টরকে কল করে। উদাহরণের জন্য নীচের কোডটি দেখুন।

আপনি যা বর্ণনা করেন তা করার জন্য আমি আপনার কোডটি পরিবর্তন করেছি। নীচে কিছু ক্যাভেট রয়েছে।

#include <iostream>

class Animal
{
public:

    typedef Animal*(*NewAnimalFunction)(void);

    virtual void makeNoise()
    {
        std::cout << "M00f!" << std::endl;
    }
};

class Dog : public Animal
{
public:

    typedef void(Dog::*BarkFunction)(void);

    typedef Dog*(*NewDogFunction)(void);

    Dog () {}

    static Dog* newDog()
    {
        return new Dog;
    }

    virtual void makeNoise ()
    {
        std::cout << "Woof!" << std::endl;
    }
};

int main(int argc, char* argv[])
{
    // Call member function via method pointer
    Dog* pDog = new Dog ();
    Dog::BarkFunction pBark = &Dog::makeNoise;

    (pDog->*pBark)();

    // Construct instance via factory method
    Dog::NewDogFunction pNew = &Dog::newDog;

    Animal* pAnimal = (*pNew)();

    pAnimal->makeNoise();

    return 0;
}

এখন যদিও আপনি পলিমারফিজমের যাদুটির জন্য ধন্যবাদের Dog*জায়গায় সাধারণত একটি ব্যবহার করতে পারেন তবে Animal*কোনও ফাংশন পয়েন্টারের ধরণটি শ্রেণিবদ্ধ শ্রেণিবিন্যাসের অনুসন্ধানের নিয়মগুলি অনুসরণ করে না । সুতরাং একটি প্রাণী পদ্ধতি পয়েন্টার একটি কুকুর পদ্ধতির পয়েন্টারের সাথে সামঞ্জস্যপূর্ণ নয়, অন্য কথায় আপনি Dog* (*)()কোনও ধরণের ভেরিয়েবলকে একটি বরাদ্দ করতে পারবেন না Animal* (*)()

স্থির newDogপদ্ধতিটি একটি কারখানার একটি সাধারণ উদাহরণ, যা কেবল নতুন দৃষ্টান্ত তৈরি করে এবং প্রদান করে। স্ট্যাটিক ফাংশন হওয়ার কারণে এটির নিয়মিত typedef(কোনও শ্রেণির বাছাইকারী নেই) রয়েছে।

উপরের উত্তরটি দিয়ে, আমি অবাক হই যে আপনার প্রয়োজনীয়তা অর্জনের জন্য এর চেয়ে ভাল উপায় যদি না থাকে। কয়েকটি নির্দিষ্ট পরিস্থিতি রয়েছে যেখানে আপনি এই ধরণের কাজটি করবেন তবে আপনার সমস্যার জন্য আরও ভাল নিদর্শন রয়েছে এমন আরও কিছু নিদর্শন রয়েছে find আপনি যা অর্জন করতে চাইছেন তা যদি আরও সাধারণ পরিভাষায় বর্ণনা করেন তবে মধুশক্তিটি আরও কার্যকর প্রমাণিত হতে পারে!

উপরের সাথে সম্পর্কিত, আপনি নিঃসন্দেহে বুস্ট বাইন্ড লাইব্রেরি এবং অন্যান্য সম্পর্কিত মডিউলগুলি খুব দরকারী বলে খুঁজে পেতে পারেন।


10
আমি 10 বছরেরও বেশি সময় ধরে সি ++ ব্যবহার করেছি এবং নিয়মিত নতুন কিছু শিখতে থাকি। আমি এর আগে কখনও শুনিনি ->*, তবে এখন আমি আশা করি এটির কখনই প্রয়োজন হবে না :)
টমাস

31

আমি মনে করি না যে এখানে কেউ ব্যাখ্যা করেছে যে একটি সমস্যা হ'ল আপনার সাধারণ ফাংশন পয়েন্টারগুলির চেয়ে " সদস্য পয়েন্টার " দরকার ।

ফাংশনে সদস্য পয়েন্টারগুলি কেবল ফাংশন পয়েন্টার নয়। বাস্তবায়নের শর্তাবলী, সংকলক একটি সাধারণ ফাংশন ঠিকানা ব্যবহার করতে পারে না কারণ সাধারণত, আপনি কল করার ঠিকানাটি জানেন না যতক্ষণ না আপনি জানেন না কোন ऑজেক্টটির জন্য সম্মান জানাতে (ভার্চুয়াল ফাংশনগুলি ভাবেন)। thisঅবশ্যই অন্তর্নিহিত প্যারামিটার সরবরাহ করার জন্য আপনাকে অবজেক্টটিও জানতে হবে।

আপনার তাদের প্রয়োজন বলেছিলেন, এখন আমি বলব যে এগুলি সত্যই এড়ানো উচিত। গুরুতরভাবে, সদস্য পয়েন্টারগুলি একটি ব্যথা। একই লক্ষ্য অর্জনকারী অবজেক্ট-ওরিয়েন্টেড ডিজাইন প্যাটার্নগুলি দেখার জন্য boost::functionবা উপরে বর্ণিত একটি বা যা কিছু ব্যবহার করা - এটি বিবেচনা করে আপনি যে পছন্দটি বেছে নেবেন তা অনেক বেশি বুদ্ধিমান ।

আপনি বিদ্যমান কোডে যে ফাংশন পয়েন্টার সরবরাহ করছে যদি তাই হয় আপনি কি সত্যিই প্রয়োজন একটি সহজ ফাংশন পয়েন্টার, আপনি ক্লাসের একটি স্ট্যাটিক সদস্য হিসেবে একটি ফাংশন লিখতে হবে। একটি স্থিতিশীল সদস্য ফাংশন বুঝতে পারে না this, সুতরাং আপনাকে একটি স্পষ্ট প্যারামিটার হিসাবে অবজেক্টটি পাস করতে হবে। পুরানো সি কোড দিয়ে কাজ করার জন্য এই লাইনগুলির সাথে একবারে একটি অসাধারণ-অসাধারণ প্রতিচ্ছবি ছিল যা ফাংশন পয়েন্টার প্রয়োজন

class myclass
{
  public:
    virtual void myrealmethod () = 0;

    static void myfunction (myclass *p);
}

void myclass::myfunction (myclass *p)
{
  p->myrealmethod ();
}

যেহেতু myfunctionসত্যই কেবল একটি সাধারণ ফাংশন (স্কোপ ইস্যুগুলি বাদ দিয়ে), একটি ফাংশন পয়েন্টারটি সাধারণ সি উপায়ে পাওয়া যাবে।

সম্পাদনা - এই ধরণের পদ্ধতিটিকে "শ্রেণি পদ্ধতি" বা "স্ট্যাটিক সদস্য ফাংশন" বলা হয়। সদস্যবিহীন ফাংশন থেকে মূল পার্থক্য হ'ল, আপনি যদি এটি শ্রেণীর বাইরে থেকে উল্লেখ করেন তবে আপনাকে অবশ্যই ::স্কোপ রেজোলিউশন অপারেটরটি ব্যবহার করে সুযোগটি নির্দিষ্ট করতে হবে । উদাহরণস্বরূপ, ফাংশন পয়েন্টার পেতে, &myclass::myfunctionএটি ব্যবহার করতে এবং কল করতে myclass::myfunction (arg);

পুরানো উইন 32 এপিআই ব্যবহার করার সময় এই জাতীয় জিনিসটি মোটামুটি সাধারণ, যা মূলত সি ++ এর পরিবর্তে সি জন্য ডিজাইন করা হয়েছিল। অবশ্যই সেই ক্ষেত্রে, প্যারামিটারটি সাধারণত পয়েন্টারের পরিবর্তে এলপিআরএএম বা অনুরূপ হয় এবং কিছু ingালাই প্রয়োজন।


'মাইফানশন' কোনও সাধারণ ফাংশন নয় যদি সাধারণভাবে আপনি সি স্টাইলের ফাংশনটি বোঝায়। 'মাইফাঙ্কশন' কে আরও সঠিকভাবে মাইক্রাসের একটি পদ্ধতি বলা হয়। শ্রেণীর পদ্ধতিগুলি সাধারণ ফাংশনের মতো নয় কারণ তাদের কিছু সি স্টাইলের ফাংশন নেই যা 'এটি' পয়েন্টার।
এরিক

3
বুস্ট ব্যবহার করার পরামর্শ দেওয়া কঠোর। পদ্ধতি পয়েন্টার ব্যবহারের জন্য ব্যবহারিক ভাল কারণ রয়েছে। বিকল্প হিসাবে উত্সাহ দেওয়ার উল্লেখকে আমি আপত্তি করি না তবে কেউ ঘৃণা করে যখন অন্য কেউ সমস্ত ঘটনা না জেনে এটি ব্যবহার করা উচিত। দামে বুস্ট আসে! এবং যদি এটি একটি এম্বেডেড প্ল্যাটফর্ম হয় তবে এটি সম্ভবত এটি সম্ভব পছন্দ নয়। এর বাইরে, আমি আপনার লেখাটি সত্যিই পছন্দ করি।
এরিক 18

@ এরিক - আপনার দ্বিতীয় পয়েন্টে, "তুমি বুস্ট ব্যবহার করবে" বলার আমি ইচ্ছা করি নি, এবং বাস্তবে আমি নিজে কখনই বুস্টকে ব্যবহার করি নি। উদ্দেশ্য (যতদূর আমি এটি 3 বছর পরে জানি) লোকদের বিকল্পের সন্ধান করা এবং কয়েকটি সম্ভাবনার তালিকা তৈরি করা উচিত ছিল। "বা যাই হোক না কেন" ইঙ্গিত দেয় যে তালিকাটি সম্পূর্ণরূপে বোঝানো নয়। সদস্য পয়েন্টারগুলির পাঠযোগ্যতার জন্য ব্যয় রয়েছে have তাদের সংক্ষিপ্ত উত্স উপস্থাপনা রান-টাইম ব্যয়ের ছদ্মবেশও তৈরি করতে পারে - বিশেষত কোনও পদ্ধতির কোনও সদস্য পয়েন্টারটিকে অবশ্যই অ-ভার্চুয়াল এবং ভার্চুয়াল পদ্ধতি উভয়ই মোকাবেলা করতে হবে এবং এটি অবশ্যই জানা উচিত।
স্টিভ 314

@ এরিক - কেবল এটিই নয়, তবে এই বিষয়গুলি সদস্য পয়েন্টারগুলির সাথে পোর্টেবলহীনতার কারণ - ভিজ্যুয়াল সি ++, কমপক্ষে অতীতে সদস্য পয়েন্টারগুলির ধরন উপস্থাপনের জন্য কিছু অতিরিক্ত ক্লু প্রয়োজন ছিল। আমি একটি এম্বেড থাকা সিস্টেমের জন্য স্ট্যাটিক ফাংশন পদ্ধতির ব্যবহার করব - পয়েন্টারের উপস্থাপনা অন্য ফাংশন পয়েন্টারের সমান, ব্যয়গুলি সুস্পষ্ট এবং কোনও বহনযোগ্যতার সমস্যা নেই। এবং স্থিতিশীল সদস্য ফাংশন দ্বারা আবৃত কলটি জানে (সংকলন সময়ে) কলটি ভার্চুয়াল কিনা তা - ভার্চুয়াল পদ্ধতিগুলির জন্য সাধারণ ভেটেবল লুকআপের বাইরে কোনও রান-টাইম চেকের প্রয়োজন নেই।
স্টিভ 314

@ এরিক - আপনার প্রথম পয়েন্টে - আমি জানি যে একটি স্ট্যাটিক সদস্য ফাংশন হ'ল সি-স্টাইলের ফাংশনের মতো নয় (সুতরাং "স্কোপ ইস্যুগুলি বাদ দিয়ে") তবে আমার সম্ভবত নামটি অন্তর্ভুক্ত করা উচিত ছিল।
স্টিভ 314

18
typedef void (Dog::*memfun)();
memfun doSomething = &Dog::bark;
....
(pDog->*doSomething)(); // if pDog is a pointer
// (pDog.*doSomething)(); // if pDog is a reference

2
হওয়া উচিত: (পিডগ -> * ডোজ কিছু) (); // যদি পিডগ পয়েন্টার হয় // (পিডগ। * ডোজ কিছু) (); // যদি পিডগ একটি রেফারেন্স হিসাবে থাকে () অপারেটরের উচ্চতর অগ্রাধিকার থাকে তবে -> * এবং। *।
টোমেক

12

ন্যূনতম চলমান উদাহরণ

main.cpp

#include <cassert>

class C {
    public:
        int i;
        C(int i) : i(i) {}
        int m(int j) { return this->i + j; }
};

int main() {
    // Get a method pointer.
    int (C::*p)(int) = &C::m;

    // Create a test object.
    C c(1);
    C *cp = &c;

    // Operator .*
    assert((c.*p)(2) == 3);

    // Operator ->*
    assert((cp->*p)(2) == 3);
}

সংকলন এবং চালান:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

উবুন্টুতে পরীক্ষিত 18.04।

আপনি প্রথম বন্ধনের ক্রম পরিবর্তন করতে বা সেগুলি বাদ দিতে পারবেন না। নিম্নলিখিতগুলি কাজ করে না:

c.*p(2)
c.*(p)(2)

জিসিসি 9.2 এর সাথে ব্যর্থ হবে:

main.cpp: In function int main()’:
main.cpp:19:18: error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in p (...)’, e.g. ‘(... ->* p) (...)’
   19 |     assert(c.*p(2) == 3);
      |

সি ++ 11 স্ট্যান্ডার্ড

.*এবং ->*একটি হয় একক অপারেটরদের এই কাজের জন্য সি ++ চালু, এবং সি উপস্থিত না

সি ++ 11 এন 3337 স্ট্যান্ডার্ড খসড়া :

  • 2.13 "অপারেটর এবং বিরামচিহ্নগুলির" সমস্ত অপারেটরের একটি তালিকা রয়েছে, এতে .*এবং রয়েছে ->*
  • 5.5 "পয়েন্টার থেকে সদস্য অপারেটর" তারা কী করে তা ব্যাখ্যা করে

11

আমি এখানে একটি পদ্ধতি থেকে ফাংশন পয়েন্টার (কোনও পদ্ধতি পয়েন্টার নয়) তৈরি করতে শিখতে এসেছি তবে এখানে উত্তরগুলির কোনওটিরই সমাধান নেই। আমি এখানে যা এলাম:

template <class T> struct MethodHelper;
template <class C, class Ret, class... Args> struct MethodHelper<Ret (C::*)(Args...)> {
    using T = Ret (C::*)(Args...);
    template <T m> static Ret call(C* object, Args... args) {
        return (object->*m)(args...);
    }
};

#define METHOD_FP(m) MethodHelper<decltype(m)>::call<m>

সুতরাং আপনার উদাহরণের জন্য আপনি এখন এটি করবেন:

Dog dog;
using BarkFunction = void (*)(Dog*);
BarkFunction bark = METHOD_FP(&Dog::bark);
(*bark)(&dog); // or simply bark(&dog)

সম্পাদনা করুন:
সি ++ 17 ব্যবহার করে আরও একটি ভাল সমাধান পাওয়া যায়:

template <auto m> struct MethodHelper;
template <class C, class Ret, class... Args, Ret (C::*m)(Args...)> struct MethodHelper<m> {
    static Ret call(C* object, Args... args) {
        return (object->*m)(args...);
    }
};

যা সরাসরি ম্যাক্রো ছাড়াই ব্যবহার করা যেতে পারে:

Dog dog;
using BarkFunction = void (*)(Dog*);
BarkFunction bark = MethodHelper<&Dog::bark>::call;
(*bark)(&dog); // or simply bark(&dog)

মডিফায়ারযুক্ত পদ্ধতিগুলির জন্য constআপনার আরও কয়েকটি বিশেষায়নের প্রয়োজন হতে পারে:

template <class C, class Ret, class... Args, Ret (C::*m)(Args...) const> struct MethodHelper<m> {
    static Ret call(const C* object, Args... args) {
        return (object->*m)(args...);
    }
};

6

সদস্য ফাংশনগুলিতে কল করতে আপনি ফাংশন পয়েন্টার কেন ব্যবহার করতে পারবেন না তার কারণ হ'ল সাধারণ ফাংশন পয়েন্টারগুলি সাধারণত ফাংশনের মেমরি ঠিকানা হয়।

সদস্য ফাংশনটি কল করতে আপনার দুটি জিনিস জানতে হবে:

  • কোন সদস্যকে ফোন করতে হবে function
  • কোন উদাহরণটি ব্যবহার করা উচিত (যার সদস্যের ফাংশন)

সাধারণ ফাংশন পয়েন্টার উভয়ই সঞ্চয় করতে পারে না। সি ++ সদস্য ফাংশন পয়েন্টারগুলি একটি সংরক্ষণ করার জন্য ব্যবহার করা হয়) যার কারণে আপনাকে কোনও সদস্য ফাংশন পয়েন্টার কল করার সময় স্পষ্টভাবে উদাহরণটি নির্দিষ্ট করতে হবে।


1
আমি এটিকে ভোট দিয়েছি তবে ওপি "কোন উদাহরণ" দিয়ে আপনি কী উল্লেখ করছেন তা না জানার ক্ষেত্রে একটি স্পষ্টকরণ পয়েন্ট যুক্ত করব would আমি অন্তর্নিহিত 'এই' পয়েন্টারটি ব্যাখ্যা করতে প্রসারিত করব।
এরিক 18

6

কোনও শ্রেণীর সদস্যের কাছে একটি ফাংশন পয়েন্টার এমন একটি সমস্যা যা বুস্ট :: ফাংশনটি ব্যবহারের পক্ষে সত্যই উপযুক্ত। ছোট উদাহরণ:

#include <boost/function.hpp>
#include <iostream>

class Dog 
{
public:
   Dog (int i) : tmp(i) {}
   void bark ()
   {
      std::cout << "woof: " << tmp << std::endl;
   }
private:
   int tmp;
};



int main()
{
   Dog* pDog1 = new Dog (1);
   Dog* pDog2 = new Dog (2);

   //BarkFunction pBark = &Dog::bark;
   boost::function<void (Dog*)> f1 = &Dog::bark;

   f1(pDog1);
   f1(pDog2);
}

2

একটি নতুন অবজেক্ট তৈরি করতে আপনি হয় উপরে বর্ণিত প্লেসমেন্ট নতুন ব্যবহার করতে পারেন, বা আপনার ক্লাসটি ক্লোন () পদ্ধতি প্রয়োগ করতে পারেন যা বস্তুর অনুলিপি তৈরি করে। তারপরে আপনি অবজেক্টের নতুন উদাহরণ তৈরি করতে উপরে বর্ণিত হিসাবে সদস্য ফাংশন পয়েন্টার ব্যবহার করে এই ক্লোন পদ্ধতিটি কল করতে পারেন। ক্লোনটির সুবিধা হ'ল কখনও কখনও আপনি বেস ক্লাসে পয়েন্টার নিয়ে কাজ করতে পারেন যেখানে আপনি অবজেক্টের ধরণটি জানেন না। এই ক্ষেত্রে একটি ক্লোন () পদ্ধতি ব্যবহার করা সহজ হতে পারে। এছাড়াও, ক্লোন () আপনি যদি চান তা যদি আপনাকে অবজেক্টের অবস্থা অনুলিপি করতে দেয়।


ক্লোনগুলি ব্যয়বহুল হতে পারে এবং পারফরম্যান্স কোনও সমস্যা বা উদ্বেগের বিষয় হলে ওপি সেগুলি এড়াতে চায় wish
এরিক

0

আমি স্ট্যান্ড :: ফাংশন এবং স্ট্যান্ড :: বাইন্ড দিয়ে এটি করেছি

আমি এই ইভেন্ট ম্যানেজার ক্লাসটি লিখেছি যা একটি নিয়ন্ত্রিত_ম্যাপে হ্যান্ডলারের একটি ভেক্টর সঞ্চয় করে যা ইভেন্টের ধরণের মানচিত্র (যা কেবল স্বাক্ষরবিহীন অন্তর্নিহিত, আমার একটি বড় নেমস্পেস-স্কোপড এনাম আছে) ইভেন্টের ধরণের হ্যান্ডলারের কাছে।

আমার ইভেন্ট ম্যানেজার টেস্ট ক্লাসে, আমি এইভাবে একটি ইভেন্ট হ্যান্ডলার সেট আপ করেছি:

auto delegate = std::bind(&EventManagerTests::OnKeyDown, this, std::placeholders::_1);
event_manager.AddEventListener(kEventKeyDown, delegate);

এখানে অ্যাডএভেন্টলিস্টনার ফাংশনটি রয়েছে:

std::vector<EventHandler>::iterator EventManager::AddEventListener(EventType _event_type, EventHandler _handler)
{
    if (listeners_.count(_event_type) == 0) 
    {
        listeners_.emplace(_event_type, new std::vector<EventHandler>());
    }
    std::vector<EventHandler>::iterator it = listeners_[_event_type]->end();
    listeners_[_event_type]->push_back(_handler);       
    return it;
}

এখানে ইভেন্টহ্যান্ডলার ধরণের সংজ্ঞা রয়েছে:

typedef std::function<void(Event *)> EventHandler;

তারপরে ইভেন্ট ম্যানেজার টেস্টগুলিতে ফিরে :: রাইসইভেন্ট, আমি এটি করি:

Engine::KeyDownEvent event(39);
event_manager.RaiseEvent(1, (Engine::Event*) & event);

ইভেন্ট ম্যানেজারের জন্য এখানে কোড :: উত্থাপন:

void EventManager::RaiseEvent(EventType _event_type, Event * _event)
{
    if (listeners_.count(_event_type) > 0)
    {
        std::vector<EventHandler> * vec = listeners_[_event_type];
        std::for_each(
            begin(*vec), 
            end(*vec), 
            [_event](EventHandler handler) mutable 
            {
                (handler)(_event);
            }
        );
    }
}

এইটা কাজ করে. আমি ইভেন্ট ম্যানেজার টেস্টস :: ওনকিডাউন-এ কল পেয়েছি। আমাকে ভেক্টরগুলি মুছে ফেলতে হবে সময় পরিষ্কার করতে, তবে একবার আমি এটি করি যে কোনও ফাঁস নেই। একটি ইভেন্ট উত্থাপন করতে আমার কম্পিউটারে প্রায় 5 টি মাইক্রোসেকেন্ড লাগে, যা প্রায় ২০০ 2008 সালে। যতক্ষণ না আমি জানি এটি যথেষ্ট উপযুক্ত এবং আমি এটি অতি হট কোডে ব্যবহার করি না।

আমি আমার নিজস্ব স্টাডি :: ফাংশন এবং এসটিডি :: বাইন্ডটি ঘূর্ণায়মান করে এবং সম্ভবত ভেক্টরগুলির আনর্ডার্ড_ম্যাপের চেয়ে অ্যারে ব্যবহার করে এটিকে দ্রুত করতে চাই, তবে সদস্য ফাংশন কীভাবে সংরক্ষণ করব তা আমি খুব একটা বুঝতে পারি নি পয়েন্টার এবং কোড থেকে কল করুন যা ক্লাস বলা হচ্ছে সম্পর্কে কিছুই জানে না। আইল্যাশের উত্তর খুব আকর্ষণীয় দেখাচ্ছে ..

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.