একটি বেসরকারী খাঁটি ভার্চুয়াল ফাংশনটি কী?


139

আমি নিম্নলিখিত শিরোনামটি একটি শিরোনাম ফাইলটিতে এসেছি:

class Engine
{
public:
    void SetState( int var, bool val );
    {   SetStateBool( int var, bool val ); }

    void SetState( int var, int val );
    {   SetStateInt( int var, int val ); }
private:
    virtual void SetStateBool(int var, bool val ) = 0;    
    virtual void SetStateInt(int var, int val ) = 0;    
};

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

উত্তর:


209

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

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

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

"সর্বজনীন ওভারলোড হওয়া নন-ভার্চুয়ালগুলি সুরক্ষিত অ-ওভারলোড ভার্চুয়ালগুলি কল করে"

এটি লুকানোর নিয়মটি সঠিকভাবে পরিচালনা করতে সহায়তা করে । আপনি এখানে এটি সম্পর্কে আরও পড়তে পারেন , তবে আমি খুব শীঘ্রই এটি ব্যাখ্যা করার চেষ্টা করব।

ভাবুন, Engineশ্রেণীর ভার্চুয়াল ফাংশনগুলিও এর ইন্টারফেস এবং এটি ওভারলোডেড ফাংশনগুলির একটি সেট যা খাঁটি ভার্চুয়াল নয়। যদি তারা খাঁটি ভার্চুয়াল হয় তবে নীচের বর্ণিত হিসাবে কেউ একই সমস্যাটির মুখোমুখি হতে পারে তবে শ্রেণীর শ্রেণিবিন্যাসের চেয়ে কম।

class Engine
{
public:
    virtual void SetState( int var, bool val ) {/*some implementation*/}
    virtual void SetState( int var, int val )  {/*some implementation*/}
};

এখন ধরে নেওয়া যাক আপনি একটি উদ্ভূত শ্রেণি তৈরি করতে চান এবং আপনাকে কেবল পদ্ধতির জন্য একটি নতুন বাস্তবায়ন সরবরাহ করতে হবে, এটি দুটি যুক্তি হিসাবে যুক্তি হিসাবে গ্রহণ করে।

class MyTurbochargedV8 : public Engine
{
public:
    // To prevent SetState( int var, bool val ) from the base class,
    // from being hidden by the new implementation of the other overload (below),
    // you have to put using declaration in the derived class
    using Engine::SetState;

    void SetState( int var, int val )  {/*new implementation*/}
};

যদি আপনি উদ্ভট ক্লাসে ব্যবহারের ঘোষণাটি (অথবা দ্বিতীয় ওভারলোডটিকে নতুন সংজ্ঞা দিতে) রাখতে ভুলে যান তবে আপনি নীচের দৃশ্যে সমস্যায় পড়তে পারেন।

MyTurbochargedV8* myV8 = new MyTurbochargedV8();
myV8->SetState(5, true);

আপনি যদি Engineসদস্যদের আড়াল না করে থাকেন তবে বিবৃতি:

myV8->SetState(5, true);

কল করবে void SetState( int var, int val )উদ্ভূত বর্গ থেকে, রূপান্তর trueকরার int

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

class MyTurbochargedV8 : public Engine
{
private:
    void SetStateInt(int var, int val )  {/*new implementation*/}
};

ভার্চুয়াল ফাংশনটি ব্যক্তিগত হতে হবে কেন? এটা কি পাবলিক হতে পারে?
ধনী

আমি ভাবছি যে হার্ব সাটার তার "ভার্চুয়ালিটি" নিবন্ধে প্রদত্ত গাইডলাইনগুলি আজও ধরে রাখে?
নুরভা

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

43

প্রাইভেট খাঁটি ভার্চুয়াল ফাংশন হ'ল নন-ভার্চুয়াল ইন্টারফেস আইডিয়মের ভিত্তি (ঠিক আছে, এটি একেবারে খাঁটি ভার্চুয়াল নয়, তবে এখনও ভার্চুয়াল রয়েছে)। অবশ্যই এটি অন্যান্য জিনিসের জন্যও ব্যবহৃত হয় তবে আমি এটি সবচেয়ে দরকারী হিসাবে খুঁজে পেয়েছি (: দুটি কথায়: একটি পাবলিক ফাংশনে, আপনি কিছু সাধারণ জিনিস (যেমন লগিং, পরিসংখ্যান ইত্যাদি) শুরুতে রাখতে পারেন এবং ফাংশনের শেষে এবং তারপরে, "মাঝখানে" এই বেসরকারী ভার্চুয়াল ফাংশনটি কল করতে, এটি নির্দিষ্ট উত্পন্ন শ্রেণীর জন্য আলাদা হবে like

class Base
{
    // ..
public:
    void f();
private:
    virtual void DerivedClassSpecific() = 0;
   // ..
};
void Base::f()
{
    //.. Do some common stuff
    DerivedClassSpecific();
    //.. Some other common stuff
}
// ..

class Derived: public Base
{
    // ..
private:
    virtual void DerivedClassSpecific();
    //..
};
void Derived::DerivedClassSpecific()
{
    // ..
}

খাঁটি ভার্চুয়াল - কেবলমাত্র উদ্ভূত শ্রেণিগুলি এটি প্রয়োগ করতে বাধ্য করে।

সম্পাদনা : এ সম্পর্কে আরও: উইকিপিডিয়া :: এনভিআই-আইডিয়াম


17

ভাল, একটির জন্য, এটি একটি উত্পন্ন শ্রেণিকে এমন কোনও ফাংশন প্রয়োগ করতে দেয় যা বেস ক্লাসটি (খাঁটি ভার্চুয়াল ফাংশন ঘোষণার সমন্বিত) কল করতে পারে।


5
যে কেবল বেস ক্লাস কল করতে পারেন!
আন্ডারস্কোর_ডি

4

সম্পাদনা: ওভাররাইড করার ক্ষমতা এবং অ্যাক্সেস / অনুরোধ করার ক্ষমতা সম্পর্কে স্পষ্ট বিবৃতি।

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

#include <iostream>

class Engine
{
public:
  void SetState( int var, bool val )
  {
    SetStateBool( var, val );
  }

  void SetState( int var, int val )
  {
    SetStateInt( var, val );
  }

private:

    virtual void SetStateBool(int var, bool val ) = 0;
    virtual void SetStateInt(int var, int val ) = 0;

};

class DerivedEngine : public Engine
{
private:
  virtual void SetStateBool(int var, bool val )
  {
    std::cout << "DerivedEngine::SetStateBool() called" << std::endl;
  }

  virtual void SetStateInt(int var, int val )
  {
    std::cout << "DerivedEngine::SetStateInt() called" << std::endl;
  }
};


int main()
{
  DerivedEngine e;
  Engine * be = &e;

  be->SetState(4, true);
  be->SetState(2, 1000);
}

Private virtualআপনার কোডের মতো বেস ক্লাসের পদ্ধতিগুলি সাধারণত টেম্পলেট পদ্ধতি ডিজাইনের প্যাটার্ন প্রয়োগ করতে ব্যবহৃত হয় । সেই নকশার ধরণটি বেস বেসে কোড পরিবর্তন না করে বেস ক্লাসে একটি অ্যালগরিদমের আচরণ পরিবর্তন করতে দেয়। উপরের কোডটি যেখানে বেস শ্রেণীর পদ্ধতিগুলি বেস শ্রেণীর নির্দেশকের মাধ্যমে আহ্বান করা হয় এটি টেম্পলেট পদ্ধতি প্যাটার্নের একটি সাধারণ উদাহরণ।


আমি দেখতে পাচ্ছি, তবে যদি উদ্ভূত শ্রেণীর যে কোনও উপায়ে একরকম অ্যাক্সেস থাকে তবে এগুলিকে ব্যক্তিগত করে কেন বিরক্ত করবেন?
BeeBand

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

কারণ আপনি ভুল শ্রেণীর মধ্যে উত্তরাধিকার দৃশ্যমানতা Engineএবং DerivedEngineকি দিয়ে কিছুই করার আছে DerivedEngine(অথবা অ্যাক্সেস, যে বিষয়টি জন্য) অথবা ওভাররাইড করতে পারবে না পারবেন না।
wilhelmtell

@ উইলহেলমটেল: দীর্ঘশ্বাস ফেললে আপনি অবশ্যই সঠিক। আমি আমার উত্তর অনুসারে আপডেট করব।
অকার্যকর

3

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

একটি সংক্ষিপ্ত ব্যাখ্যা দেবএক্স.কম এর সন্ধান করা যেতে পারে ।


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

ভার্চুয়ালতা সম্পর্কে একটি আকর্ষণীয় নিবন্ধ পাওয়া যাবে ।


2
@ জেন্টলম্যান ... এইচএমএম কলিন ডি বেনেটের মন্তব্যে স্ক্রোল করুন। তিনি মনে করেন যে "একটি প্রাইভেট ভার্চুয়াল ফাংশন ডাইরেক্ট ক্লাস দ্বারা ওভাররাইড করা যেতে পারে, তবে কেবল বেস ক্লাসের মধ্যে থেকে কল করা যেতে পারে।" @ মিশেল গোল্ডস্টেইনও এরকম চিন্তা করে।
BeBBand

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

@ জেন্টলম্যান: না, আমি ভুলিনি। আমি আমার মন্তব্যে একটি টাইপো করেছি। "বেস ক্লাস পদ্ধতিতে অ্যাক্সেস" পরিবর্তে আমার লেখা উচিত ছিল "বেস শ্রেণীর পদ্ধতিগুলিকে ওভাররাইড করতে পারে"। উত্সযুক্ত শ্রেণিটি অবশ্যই বেসরকারী ভার্চুয়াল বেস শ্রেণি পদ্ধতিটি ওভাররাইড করতে পারে এমনকি যদি এটি সেই বেস শ্রেণীর পদ্ধতিতে অ্যাক্সেস না করে। আপনি যে DevX.com নিবন্ধটি নির্দেশ করেছেন তা ভুল ছিল (জনসাধারণের উত্তরাধিকার)। আমার উত্তরে কোডটি চেষ্টা করে দেখুন। বেসরকারী ভার্চুয়াল বেস শ্রেণীর পদ্ধতি থাকা সত্ত্বেও, উত্পন্ন শ্রেণি এটির ওভাররাইড করতে সক্ষম। আসুন বেসরকারী ভার্চুয়াল বেস শ্রেণীর পদ্ধতিটিকে অনুরোধ করার দক্ষতার সাথে ওভাররাইড করার ক্ষমতাটিকে বিভ্রান্ত করা উচিত না।
অকার্যকর

@ জেন্টলম্যান: @ উইলহেল্মটেল আমার উত্তর / মন্তব্যে ত্রুটিটি নির্দেশ করেছেন। বেস বর্গ পদ্ধতির উত্স বর্গ অ্যাক্সেসযোগ্যতায় প্রভাবিত উত্তরাধিকার সম্পর্কে আমার দাবি বন্ধ ছিল। আমি আপনার উত্তরের আপত্তিজনক মন্তব্যটি সরিয়েছি।
অকার্যকর

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

0

টিএল; ডিআর উত্তর:

আপনি এটিকে অন্য স্তরের এনক্যাপসুলেশনের মতো আচরণ করতে পারেন - কোথাও সুরক্ষিত এবং প্রাইভেটের মধ্যে : আপনি শিশু শ্রেণি থেকে এটি কল করতে পারবেন না, তবে আপনি এটিকে ওভাররাইড করতে পারেন।

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

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