সি ++ প্রতিনিধি কী?


147

সি ++ তে প্রতিনিধি সম্পর্কে সাধারণ ধারণা কী? এগুলি কী, তারা কীভাবে ব্যবহৃত হয় এবং কীসের জন্য ব্যবহৃত হয়?

আমি তাদের সম্পর্কে প্রথমে একটি 'ব্ল্যাক বক্স' উপায়ে শিখতে চাই, তবে এই জিনিসগুলির সাহস সম্পর্কে কিছুটা তথ্যও দুর্দান্ত।

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

এই দুটি কোড প্রকল্পের নিবন্ধগুলি আমার অর্থটি বোঝায় তবে বিশেষত সংক্ষিপ্তভাবে নয়:


4
আপনি নেট। এর অধীনে পরিচালিত সি ++ এর কথা বলছেন?
ডেসব্লিংকনলাইট


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

6
2 বছর অপেক্ষা করুন ?;)
র‌্যাঙ্ক 1

6
এখনও অপেক্ষা করা হচ্ছে ...
গ্রিম দ্য ওপেনার

উত্তর:


173

সি ++ তে প্রতিনিধি অর্জনের জন্য আপনার কাছে অবিশ্বাস্য পছন্দ রয়েছে। এই যে আমার মনে আসে।


বিকল্প 1: ফান্টেক্টর:

প্রয়োগ করে একটি ফাংশন অবজেক্ট তৈরি করা যেতে পারে operator()

struct Functor
{
     // Normal class/struct members

     int operator()(double d) // Arbitrary return types and parameter list
     {
          return (int) d + 1;
     }
};

// Use:
Functor f;
int i = f(3.14);

বিকল্প 2: ল্যাম্বদা এক্সপ্রেশন ( কেবলমাত্র C ++ 11 )

// Syntax is roughly: [capture](parameter list) -> return type {block}
// Some shortcuts exist
auto func = [](int i) -> double { return 2*i/1.15; };
double d = func(1);

বিকল্প 3: ফাংশন পয়েন্টার

int f(double d) { ... }
typedef int (*MyFuncT) (double d);
MyFuncT fp = &f;
int a = fp(3.14);

বিকল্প 4: সদস্য ফাংশন পয়েন্টার (দ্রুত সমাধান)

দেখুন ফাস্ট সি ++ প্রতিনিধি (চালু কোড প্রোজেক্ট )।

struct DelegateList
{
     int f1(double d) { }
     int f2(double d) { }
};

typedef int (DelegateList::* DelegateType)(double d);

DelegateType d = &DelegateList::f1;
DelegateList list;
int a = (list.*d)(3.14);

বিকল্প 5: স্ট্যান্ড :: ফাংশন

(বা boost::functionযদি আপনার স্ট্যান্ডার্ড লাইব্রেরি এটি সমর্থন করে না)। এটি ধীর, তবে এটি সবচেয়ে নমনীয়।

#include <functional>
std::function<int(double)> f = [can be set to about anything in this answer]
// Usually more useful as a parameter to another functions

বিকল্প 6: বাঁধাই ( স্ট্যান্ড :: বাইন্ড ব্যবহার করে )

উদাহরণস্বরূপ সদস্য ফাংশনটিতে কল করার জন্য সুবিধাজনক কিছু পরামিতি সেট করার অনুমতি দেয়।

struct MyClass
{
    int DoStuff(double d); // actually a DoStuff(MyClass* this, double d)
};

std::function<int(double d)> f = std::bind(&MyClass::DoStuff, this, std::placeholders::_1);
// auto f = std::bind(...); in C++11

বিকল্প 7: টেমপ্লেট

যুক্তি তালিকার সাথে মেলে যতক্ষণ না কিছু গ্রহণ করুন anything

template <class FunctionT>
int DoSomething(FunctionT func)
{
    return func(3.14);
}

2
দুর্দান্ত তালিকা, +1। তবে, কেবল দুটি এখানে প্রতিনিধি হিসাবে গণনা করেন - ল্যাম্বডাস এবং বস্তুটি ফিরে এসেছিল std::bindএবং উভয়ই একই কাজ করে, লাম্বডাস ব্যতীত এই অর্থে বহুরূপী নয় যে তারা বিভিন্ন যুক্তির ধরণগুলি গ্রহণ করতে পারে।
জিও

1
@ জেএন: আপনি কেন ফাংশন পয়েন্টার ব্যবহার না করার পরামর্শ দিচ্ছেন তবে সদস্য পদ্ধতি পয়েন্টার ব্যবহার করে ঠিক আছে বলে মনে হচ্ছে? তারা ঠিক অভিন্ন!
ম্যাথিউ এম।

1
@MatthieuM। : ন্যায্য বিন্দু. আমি ফাংশন পয়েন্টারগুলিকে উত্তরাধিকার হিসাবে বিবেচনা করছিলাম তবে এটি সম্ভবত আমার ব্যক্তিগত স্বাদ।
জেএন

1
@ শিও: আমার প্রতিনিধি সম্পর্কে আমার ধারণা বরং অভিজ্ঞতাবাদী। হতে পারে আমি খুব বেশি ফাংশন অবজেক্ট এবং ডেলিগেটকে মিশ্রিত করছি (আমার আগের সি # অভিজ্ঞতাকে দোষ দিন)।
জেএন

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

37

একটি প্রতিনিধি একটি শ্রেণি যা কোনও পয়েন্টার বা কোনও অবজেক্টের উদাহরণের রেফারেন্সকে আবৃত করে, সেই বস্তুর শ্রেণীর একটি সদস্য পদ্ধতি সেই অবজেক্টের উদাহরণটিতে ডাকা হয় এবং সেই কলটি ট্রিগার করার জন্য একটি পদ্ধতি সরবরাহ করে।

এখানে একটি উদাহরণ:

template <class T>
class CCallback
{
public:
    typedef void (T::*fn)( int anArg );

    CCallback(T& trg, fn op)
        : m_rTarget(trg)
        , m_Operation(op)
    {
    }

    void Execute( int in )
    {
        (m_rTarget.*m_Operation)( in );
    }

private:

    CCallback();
    CCallback( const CCallback& );

    T& m_rTarget;
    fn m_Operation;

};

class A
{
public:
    virtual void Fn( int i )
    {
    }
};


int main( int /*argc*/, char * /*argv*/ )
{
    A a;
    CCallback<A> cbk( a, &A::Fn );
    cbk.Execute( 3 );
}

কলটি ট্রিগার করার জন্য কোন পদ্ধতি সরবরাহ করে? প্রতিনিধি? কীভাবে? ফাংশন পয়েন্টার?
স্যার ইয়াকালট

ডেলিগেট ক্লাস এমন একটি পদ্ধতি অফার করবে Execute()যা ডেলিগেটের মোড়কে বস্তুর উপর ফাংশন কলটি ট্রিগার করে।
গ্রিম দ্য Opiner

4
এক্সিকিউটের পরিবর্তে, আমি আপনার ক্ষেত্রে কল অপারেটর - অকার্যকর CCallback :: অপারেটর () (ইনট) - কে ওভাররাইড করার জন্য সুপারিশ করব। এর কারণ জেনেরিক প্রোগ্রামিংয়ে রয়েছে, কলযোগ্য বস্তুগুলিকে কোনও ফাংশনের মতো বলা হবে বলে আশা করা হচ্ছে। o.Execute (5) বেমানান হবে তবে o (5) কলযোগ্য টেমপ্লেট আর্গুমেন্ট হিসাবে ভাল ফিট করবে। এই শ্রেণিটিও জেনারালাইজড করা যেতে পারে তবে আমি ধরে নিয়েছি আপনি ব্রেভিটির জন্য এটি সহজ রেখেছেন (যা একটি ভাল জিনিস)। N নিটপিক ব্যতীত, এটি একটি খুব দরকারী বর্গ।
ডেভিড পিটারসন

18

সি ++ প্রতিনিধি বাস্তবায়নের প্রয়োজনীয়তা সি ++ সম্প্রদায়ের কাছে দীর্ঘস্থায়ী এমব্র্যাসমেন্ট। প্রতিটি সি ++ প্রোগ্রামার তাদের থাকতে পছন্দ করবে, তাই তারা শেষ পর্যন্ত এগুলি ব্যবহার করে যে সত্য:

  1. std::function() হিপ অপারেশনগুলি ব্যবহার করে (এবং মারাত্মক এম্বেডেড প্রোগ্রামিংয়ের হাতের নাগালের বাইরে)।

  2. অন্যান্য সমস্ত বাস্তবায়ন বহনযোগ্যতা বা বৃহত্তর বা কম ডিগ্রীতে মান অনুসারে ছাড় দেয় (দয়া করে বিভিন্ন প্রতিনিধি বাস্তবায়নগুলি এখানে এবং কোডপোজেজে পরিদর্শন করে যাচাই করুন)। আমি এখনও এমন একটি বাস্তবায়ন দেখতে পাই যা বুনো পুনরায় ব্যাখ্যা_কাস্ট ব্যবহার করে না, নেস্টেড ক্লাস "প্রোটোটাইপস" যা আশা করে ব্যবহারকারীর দ্বারা পাস করা একই আকারের ফাংশন পয়েন্টার তৈরি করে, প্রথম ফরোয়ার্ড ডিক্লেয়ারের মতো সংকলক ট্রিকস, তারপরে টাইপডেফ আবার ঘোষণা করে, এবার অন্য শ্রেণি বা অনুরূপ ছায়াময় কৌশল থেকে উত্তরাধিকারী। এটি যে বাস্তবায়নকারীদের তৈরি করেছিল তাদের পক্ষে এটি দুর্দান্ত সাফল্য, যদিও সি ++ কীভাবে বিকশিত হয় তা এখনও একটি দুঃখজনক টেস্টিমনি।

  3. কেবলমাত্র এটি খুব কমই চিহ্নিত করা হয়েছে যে এখন 3 সি ++ এর বেশি স্ট্যান্ডার্ড রিভিশন, প্রতিনিধিদের সঠিকভাবে সম্বোধন করা হয়নি। (বা ভাষার বৈশিষ্ট্যগুলির অভাব যা সরাসরি ডেলিগেটের বাস্তবায়নের অনুমতি দেয়))

  4. যেভাবে সি ++ 11 ল্যাম্বদা ফাংশনগুলি স্ট্যান্ডার্ড দ্বারা সংজ্ঞায়িত করা হয়েছে (প্রতিটি ল্যাম্বডায় বেনামে, বিভিন্ন ধরণের রয়েছে), কিছু ব্যবহারের ক্ষেত্রে পরিস্থিতিটি কেবল উন্নত হয়েছে। কিন্তু (ডিএলএল) লাইব্রেরি এপিআইতে প্রতিনিধি ব্যবহারের ক্ষেত্রে, লাম্বডাস একা এখনও ব্যবহারযোগ্য নয়। এখানকার সাধারণ কৌশলটি হ'ল প্রথমে ল্যাম্বডাকে একটি স্টাডি :: ফাংশনে প্যাক করা এবং তারপরে এটিআইপি জুড়ে পাস করা।


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

3
আমি এম্বেড থাকা সিস্টেমে গাদা ছাড়াই স্টাডি :: ফাংশন ব্যবহার করছি এবং এটি এখনও কার্যকর হয়।
প্রসাদ

1
std::functionসর্বদা গতিশীলভাবে বরাদ্দ দেয় না
অরবিট

3
এই উত্তরটি একটি আসল উত্তরের চেয়ে বেশি
বেদনাদায়ক

8

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

উদাহরণস্বরূপ - আপনি এগুলি কোনও নির্দিষ্ট ফাংশনে নির্দেশ করতে পারেন এবং আপনি এগুলি চারপাশে পাস করতে পারেন এবং যখনই এবং যেখানে খুশি কল করতে পারেন।

এখানে খুব ভাল উদাহরণ রয়েছে:


4

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

class SomeClass
{
    in someMember;
    int SomeFunc( int);

    static void EventFunc( void* this__, int a, int b, int c)
    {
        SomeClass* this_ = static_cast< SomeClass*>( this__);

        this_->SomeFunc( a );
        this_->someMember = b + c;
    }
};

void ScheduleEvent( void (*delegateFunc)( void*, int, int, int), void* delegateContext);

    ...
    SomeClass* someObject = new SomeObject();
    ...
    ScheduleEvent( SomeClass::EventFunc, someObject);
    ...

1

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

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