বাস্তবায়নের সাথে খাঁটি ভার্চুয়াল ফাংশন


176

আমার প্রাথমিক বোঝাপড়াটি হ'ল খাঁটি ভার্চুয়াল ফাংশনের জন্য কোনও বাস্তবায়ন নেই, তবে আমাকে বলা হয়েছিল যে খাঁটি ভার্চুয়াল ফাংশনের বাস্তবায়ন থাকতে পারে।

class A {
public:
    virtual void f() = 0;
};

void A::f() {
    cout<<"Test"<<endl;
}

উপরে কোড ঠিক আছে?

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

উত্তর:


215

একটি খাঁটি virtualফাংশন অবশ্যই একটি উদ্ভূত প্রকারে প্রয়োগ করা উচিত যা সরাসরি তাত্ক্ষণিকভাবে প্রয়োগ করা হবে, তবে বেস প্রকারটি এখনও বাস্তবায়ন সংজ্ঞায়িত করতে পারে। একটি উত্পন্ন শ্রেণি সম্পূর্ণরূপে স্কোপড নামটি ব্যবহার করে ( A::f()যদি উদাহরণস্বরূপ - যদি A::f()থাকত publicবা হয়) দ্বারা বেস ক্লাস বাস্তবায়ন (যদি অ্যাক্সেসের অনুমতিগুলি এটির অনুমতি দেয়) স্পষ্টভাবে কল করতে পারে protected। কিছুটা এইরকম:

class B : public A {

    virtual void f() {
        // class B doesn't have anything special to do for f()
        //  so we'll call A's

        // note that A's declaration of f() would have to be public 
        //  or protected to avoid a compile time problem

        A::f();
    }

};

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

মনে রাখবেন যে এটি ভাষা দ্বারা অনুমোদিত হলেও এটি এমন কিছু নয় যা আমি সাধারণত ব্যবহৃত দেখি (এবং এটি করা যেতে পারে এটি বেশিরভাগ সি ++ প্রোগ্রামার এমনকি অভিজ্ঞ ব্যক্তিদেরও অবাক করে বলে মনে হয়)।


1
এটি প্রোগ্রামারদের কেন বিস্মিত করে তা আপনি যোগ করতে ভুলে গেছেন: এটি কারণ ইনলাইন সংজ্ঞা মান দ্বারা নিষিদ্ধ। খাঁটি ভার্চুয়াল পদ্ধতির সংজ্ঞা থাকতে হবে deported। (হয় .inl বা .cpp এ সাধারণ ফাইল-নামকরণের অনুশীলনগুলি উল্লেখ করে)।
v.oddou

সুতরাং এই কলিং পদ্ধতিটি স্থির পদ্ধতি সদস্য কলিংয়ের সমান। জাভাতে কিছু ধরণের শ্রেণিবদ্ধ পদ্ধতি।
স্যানি লুক

2
"সাধারণত ব্যবহৃত হয় না" == খারাপ অভ্যাস? আমি ঠিক একই আচরণের সন্ধান করছিলাম, এনভিআই বাস্তবায়নের চেষ্টা করছিলাম। এবং এনভিআই আমার কাছে ভাল অনুশীলন বলে মনে হচ্ছে।
সাসকিয়া

5
এটা তোলে এর মূল্য যে ইশারা তৈরীর একটি :: চ () বিশুদ্ধ উপায়ে যে বি আবশ্যক চ (বাস্তবায়ন) (অন্যথায় বি বিমূর্ত এবং uninstantiable হবে)। এবং @ মিশেলবুর যেমন উল্লেখ করেছেন, A :: f () এর জন্য একটি বাস্তবায়ন সরবরাহ করার অর্থ B এটি f () সংজ্ঞায়িত করতে ব্যবহার করতে পারে।
নির্ভীক_ফুল

2
আইআইআরসি, স্কট মায়ারের তাঁর ক্লাসিক বই "আরও কার্যকর সি ++" র একটিতে এই প্রশ্নের ব্যবহারের ক্ষেত্রে একটি চমৎকার নিবন্ধ রয়েছে
ইরিসিস

75

স্পষ্টতই, আপনি ভুল বোঝা যাচ্ছেন = 0; ভার্চুয়াল ফাংশন মানে।

= 0 এর অর্থ, উত্পন্ন শ্রেণিগুলির অবশ্যই একটি বাস্তবায়ন সরবরাহ করতে হবে, বেস ক্লাসটি বাস্তবায়ন সরবরাহ করতে পারে না।

অনুশীলনে, আপনি যখন ভার্চুয়াল ফাংশনটিকে খাঁটি (= 0) হিসাবে চিহ্নিত করেন, তখন একটি সংজ্ঞা প্রদানের খুব কম পয়েন্ট থাকে, কারণ বেস: ফাংশন (...) এর মাধ্যমে কেউ সুস্পষ্টভাবে এটি না করা হলে এটি কখনই ডাকা হবে না the বেস ক্লাসের কনস্ট্রাক্টর প্রশ্নযুক্ত ভার্চুয়াল ফাংশনটিকে কল করে।


9
এটি ভুল। আপনি যদি আপনার খাঁটি ভার্চুয়াল শ্রেণির নির্মাতায় সেই খাঁটি ভার্চুয়াল ফাংশনটি প্রার্থনা করেন তবে খাঁটি ভার্চুয়াল কল করা হবে। কোন ক্ষেত্রে আপনার আরও ভাল একটি বাস্তবায়ন আছে।
rmn

@ আরএমএন, হ্যাঁ, আপনি নির্মাতাদের ভার্চুয়াল কল সম্পর্কে ঠিক বলেছেন। আমি উত্তর আপডেট। আশা করি সবাই অবশ্য এটি করতে না জানে। :)
টেরি মাহাফি 21

3
প্রকৃতপক্ষে, কোনও নির্মাণকারীর কাছ থেকে একটি বেস খাঁটি কল করলে ফলাফল বাস্তবায়িত-সংজ্ঞায়িত আচরণের ফলাফল হয়। ভিসি ++ এ, এটি একটি_পরিকাল কল ক্রাশের সমান।
ওফেক শিলন

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

1
কনস্ট্রাক্টর এবং ডেস্ট্রাক্টরগুলিতে ভার্চুয়াল ফাংশনগুলি ভার্চুয়াল নয়
জেস্পার জুহল

20

এর সুবিধাটি হ'ল এটি উদ্ভূত প্রকারগুলিকে এখনও পদ্ধতিটিকে ওভাররাইড করতে বাধ্য করে তবে এটি একটি ডিফল্ট বা অ্যাডিটিভ বাস্তবায়ন সরবরাহ করে।


1
ডিফল্ট বাস্তবায়ন হলে আমি কেন জোর করতে চাই? এটি স্বাভাবিক ভার্চুয়াল ফাংশনগুলির মতো শোনাচ্ছে। যদি এটি কেবল একটি সাধারণ ভার্চুয়াল ফাংশন ছিল, আমি হয় ওভাররাইড করতে পারি এবং যদি আমি না করি, তবে একটি ডিফল্ট বাস্তবায়ন সরবরাহ করা হবে (বেসের বাস্তবায়ন)।
স্ট্যাকএক্সচেঞ্জ 123

19

যদি আপনার কাছে কোড থাকে যা ডেরাইভিং ক্লাস দ্বারা চালিত করা উচিত তবে আপনি এটি সরাসরি সম্পাদন করতে চান না - এবং আপনি এটিকে ওভাররেড করতে বাধ্য করতে চান।

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

খাঁটি ভার্চুয়াল ফাংশনগুলির একটি বুদ্ধিমান ব্যবহার একটি খাঁটি ভার্চুয়াল ডেস্ট্রাক্টরকে "অ-চূড়ান্ত" কীওয়ার্ড হিসাবে নির্দিষ্ট করে।

নিম্নলিখিত কোডটি আশ্চর্যজনকভাবে সঠিক:

class Base {
public:
  virtual ~Base() = 0;
};

Base::~Base() {}

class Derived : public Base {};

int main() { 
  // Base b; -- compile error
  Derived d; 
}

1
বেস শ্রেণীর ধ্বংসকারীদের সর্বদা যাইহোক, ভার্চুয়াল বা না এবং খাঁটি বা না বলা হয়; অন্যান্য ক্রিয়াকলাপগুলির সাথে আপনি গ্যারান্টি দিতে পারবেন না যে কোনও ওভাররাইডিং ভার্চুয়াল ফাংশন বেস ক্লাসের প্রয়োগটি বেস ক্লাসের সংস্করণ খাঁটি কিনা তা কল করবে।
সিবি বেইলি

1
কোডটি ভুল। ভাষার একটি সিনট্যাক্স গির্জার কারণে আপনার অবশ্যই শ্রেণীর সংজ্ঞার বাইরে ডটারটি সংজ্ঞায়িত করতে হবে।

@ রজার: ধন্যবাদ, এটি আসলে আমাকে সাহায্য করেছিল - এটিই আমি ব্যবহার করছি কোডটি, এটি এমএসভিসির অধীনে সূক্ষ্ম সংকলন করে, তবে আমার ধারণা এটি পোর্টেবল হবে না।
কর্নেল কিসিলেউইচজ


4

হ্যাঁ এটি সঠিক। আপনার উদাহরণে, এ থেকে প্রাপ্ত ক্লাসগুলি ইন্টারফেস এফ () এবং একটি ডিফল্ট বাস্তবায়ন উভয়েরই উত্তরাধিকার সূত্রে প্রাপ্ত। তবে আপনি উদ্ভূত শ্রেণিগুলিকে মেথড এফ () প্রয়োগ করতে বাধ্য করেন (এমনকি এটি কেবলমাত্র এ দ্বারা সরবরাহিত ডিফল্ট বাস্তবায়নকে কল করা হয়)।

স্কট মায়ার্স কার্যকর সি ++ (দ্বিতীয় সংস্করণ) এ এটি আলোচনা করেছেন আইটেম # 36 ইন্টারফেসের উত্তরাধিকার এবং বাস্তবায়নের উত্তরাধিকারের মধ্যে পার্থক্য। আইটেম নম্বরটি সর্বশেষ সংস্করণে পরিবর্তিত হতে পারে।


4

কোনও দেহ সহ বা ছাড়া বিশুদ্ধ ভার্চুয়াল ফাংশনগুলির সহজ অর্থ হ'ল উদ্ভূত প্রকারগুলি তাদের নিজস্ব বাস্তবায়ন সরবরাহ করতে হবে।

বেস ক্লাসে খাঁটি ভার্চুয়াল ফাংশন সংস্থাগুলি কার্যকর যদি আপনার উদ্ভূত শ্রেণিগুলি আপনার বেস শ্রেণীর প্রয়োগকে কল করতে চায়।


2

'ভার্চুয়াল শূন্যস্থান ফু () = 0;' সিনট্যাক্সের অর্থ এই নয় যে আপনি বর্তমান শ্রেণিতে ফু () প্রয়োগ করতে পারবেন না, আপনি পারেন can এর অর্থ এই নয় যে আপনি অবশ্যই এটি উদ্ভূত শ্রেণিতে প্রয়োগ করতে পারেন । আমাকে চড় মারার আগে আসুন ডায়মন্ড সমস্যাটি পর্যবেক্ষণ করুন: (অন্তর্ভুক্ত কোড, মনে রাখবেন)।

class A
{
public: 
    virtual void foo()=0;
    virtual void bar();
}

class B : public virtual A
{
public:
    void foo() { bar(); }
}

class C : public virtual A
{
public:
    void bar();
}

class D : public B, public C
{}

int main(int argc, const char* argv[])
{
    A* obj = new D();
    **obj->foo();**
    return 0;
}

এখন, আপত্তি-> ফু () অনুরোধের ফলাফল বি :: ফু () এবং তারপরে সি :: বার () এ পাবে।

আপনি দেখুন ... খাঁটি ভার্চুয়াল পদ্ধতিগুলি ডেরিভড ক্লাসগুলিতে প্রয়োগ করতে হবে না (foo () ক্লাস সি তে কোনও প্রয়োগ নেই - সংকলক সংকলন করবে) সি ++ এ প্রচুর ফাঁক রয়েছে।

আশা করি আমি সাহায্য করতে পারি :-)


5
এটি সমস্ত উদ্ভূত শ্রেণিতে প্রয়োগ করা দরকার হয় না, তবে এটি ইনস্ট্রিত করার উদ্দেশ্যে আপনি যে সমস্ত উদ্ভূত শ্রেণিতে প্রয়োগ করতে চান তা অবশ্যই প্রয়োগ করা উচিত। আপনি Cনিজের উদাহরণে কোনও ধরণের বস্তু ইনস্ট্যান্ট করতে পারবেন না । আপনি প্রকারের একটি বস্তু instantiate করতে Dকারণ এটি তার বাস্তবায়ন পায় fooথেকে B
ইয়ংজান

0

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

class Foo
{
   virtual ~Foo() = 0;
   void bar1() {}
   void bar2(int x) {}
   // other methods
};

Foo::~Foo()
{
}

এই কৌশলটি Fooক্লাসটিকে বিমূর্ত করে তোলে এবং ফলস্বরূপ ক্লাসটি সরাসরি ইনস্ট্যান্ট করা অসম্ভব। Fooক্লাসটি বিমূর্ত করার জন্য আপনি একটি অতিরিক্ত খাঁটি ভার্চুয়াল পদ্ধতি যুক্ত করেননি ।

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