আমি কখন সি ++ ব্যক্তিগত উত্তরাধিকার ব্যবহার করব?


116

সুরক্ষিত উত্তরাধিকারের বিপরীতে, সি ++ ব্যক্তিগত উত্তরাধিকার মূলধারার সি ++ বিকাশে প্রবেশের পথ খুঁজে পেয়েছে। তবে, এখনও আমি এটির জন্য ভাল ব্যবহার খুঁজে পাইনি।

আপনি ছেলেরা কখন এটি ব্যবহার করবেন?

c++  oop 

উত্তর:


60

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

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

class ClassSealer {
private:
   friend class Sealed;
   ClassSealer() {}
};
class Sealed : private virtual ClassSealer
{ 
   // ...
};
class FailsToDerive : public Sealed
{
   // Cannot be instantiated
};

সিল তাত্ক্ষণিক করা যেতে পারে। এটি ক্লাসসিলার থেকে প্রাপ্ত এবং এটি বন্ধু হিসাবে সরাসরি প্রাইভেট কনস্ট্রাক্টরকে কল করতে পারে।

FailsToDerive কম্পাইল না যেমন কল করতে হবে ClassSealer কন্সট্রাকটর সরাসরি (ভার্চুয়াল উত্তরাধিকার প্রয়োজন), কিন্তু এটা ব্যক্তিগত নয় হিসাবে পারেন নামমুদ্রাম্কিত শ্রেণী এবং এই ক্ষেত্রে FailsToDerive এক বন্ধু নয় ClassSealer


সম্পাদনা

মন্তব্যে উল্লেখ করা হয়েছিল যে সিআরটিপি ব্যবহারের সময় এটিকে জেনেরিক করা যায় না। সি ++ ১১ টি স্ট্যান্ডার্ড আর্গুমেন্টের সাথে বন্ধুত্বের জন্য আলাদা সিনট্যাক্স সরবরাহ করে সেই সীমাবদ্ধতাটিকে সরিয়ে দেয়:

template <typename T>
class Seal {
   friend T;          // not: friend class T!!!
   Seal() {}
};
class Sealed : private virtual Seal<Sealed> // ...

অবশ্যই এটি সমস্ত বিচক্ষণ, যেহেতু সি ++ 11 finalঠিক এই উদ্দেশ্যে একটি প্রাসঙ্গিক কীওয়ার্ড সরবরাহ করে:

class Sealed final // ...

এটি একটি দুর্দান্ত কৌশল। আমি এটিতে একটি ব্লগ এন্ট্রি লিখব।

1
প্রশ্ন: আমরা যদি ভার্চুয়াল উত্তরাধিকার ব্যবহার না করি, তবে ফেলস টো ডেরিভ সংকলন করবে। সঠিক?

4
+1 টি। @ সাশা: সঠিক, ভার্চুয়াল উত্তরাধিকার প্রয়োজন যেহেতু সর্বাধিক উদ্ভূত শ্রেণি সর্বদা কার্যত উত্তরাধিকারসূত্রে প্রাপ্ত বর্গের নির্মাতাদের সরাসরি ডাকে, যা সাধারণ উত্তরাধিকারের ক্ষেত্রে নয়।
j_random_hacker

5
আপনি সিল করতে চান এমন প্রতিটি শ্রেণীর জন্য একটি কাস্টম ক্লাসসিলার তৈরি না করেই এটি জেনেরিক করা যায়! এটি পরীক্ষা করে দেখুন: ClassCealer class সুরক্ষিত: ClassSealer () {}}; এখানেই শেষ.

+1 ইরাইমিলঞ্জ, খুব দুর্দান্ত! বিটিডাব্লু আমি সিআরটিপি ব্যবহার সম্পর্কে আপনার আগের মন্তব্যটি (এখন মুছে ফেলা) দেখেছি: আমার মনে হয় যে বাস্তবে এটি কাজ করা উচিত, টেমপ্লেট বন্ধুদের জন্য সিনট্যাক্সটি সঠিকভাবে পাওয়া ঠিক মুশকিল। তবে যে কোনও ক্ষেত্রে আপনার অ-টেম্পলেট সমাধানটি আরও দুর্দান্ত :) :)
j_random_hacker

138

আমি সব সময় এটি ব্যবহার করি। আমার মাথার উপরের অংশের কয়েকটি উদাহরণ:

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

একটি সাধারণ উদাহরণ একটি এসটিএল ধারক থেকে ব্যক্তিগতভাবে প্রাপ্ত হয়:

class MyVector : private vector<int>
{
public:
    // Using declarations expose the few functions my clients need 
    // without a load of forwarding functions. 
    using vector<int>::push_back;
    // etc...  
};
  • অ্যাডাপ্টার প্যাটার্নটি বাস্তবায়ন করার সময়, অভিযোজিত শ্রেণীর কাছ থেকে ব্যক্তিগতভাবে উত্তরাধিকার সূত্রে কোনও সংযুক্ত উদাহরণে এগিয়ে যাওয়া সংরক্ষণ করে।
  • একটি ব্যক্তিগত ইন্টারফেস বাস্তবায়নের জন্য। এটি প্রায়শই পর্যবেক্ষক প্যাটার্ন সহ আসে। সাধারণত আমার পর্যবেক্ষক ক্লাস, মাইক্লাস বলে, কিছু সাবজেক্টের সাথে নিজেকে সাবস্ক্রাইব করে । তারপরে, কেবল মাইক্লাসকে মাইক্লাস -> পর্যবেক্ষক রূপান্তর করতে হবে। সিস্টেমটির বাকী অংশগুলি সম্পর্কে এটি জানার দরকার নেই, তাই ব্যক্তিগত উত্তরাধিকার সূচিত হয়।

4
@ কৃষ্ণা: আসলে, আমি তা মনে করি না। এখানে কেবল একটি কারণ রয়েছে: অলসতা, শেষটি বাদে, এটি চারপাশে কাজ করা আরও কঠিন।
ম্যাথিউ এম।

11
এত অলসতা না (যদি আপনি এটি ভাল উপায়ে না বোঝেন)। এটি কোনও অতিরিক্ত কাজ ছাড়াই প্রকাশিত ফাংশনগুলির নতুন ওভারলোডগুলি তৈরি করার অনুমতি দেয়। যদি C ++ 1x এ থাকে তবে তারা এতে 3 টি নতুন ওভারলোড যুক্ত করে push_back, MyVectorবিনামূল্যে পান।
ডেভিড স্টোন

@ ডেভিডস্টোন, আপনি কি এটি একটি টেম্পলেট পদ্ধতিতে করতে পারবেন না?
জুলিয়ান__ 20'15

5
@ জুলিয়েন__: হ্যাঁ, আপনি লিখতে পারেন template<typename... Args> constexpr decltype(auto) f(Args && ... args) noexcept(noexcept(std::declval<Base &>().f(std::forward<Args>(args)...)) and std::is_nothrow_move_constructible<decltype(std::declval<Base &>().f(std::forward<Args>(args)...))>) { return m_base.f(std::forward<Args>(args)...); }বা ব্যবহার করে লিখতে পারেন Base::f;। আপনি যদি ব্যক্তিগত উত্তরাধিকার এবং একটি usingবিবৃতি আপনাকে প্রদত্ত বেশিরভাগ কার্যকারিতা এবং নমনীয়তা চান তবে প্রতিটি ফাংশনের জন্য আপনার কাছে সেই দৈত্য রয়েছে (এবং ভুলে যাবেন না constএবং volatileওভারলোডগুলি!)।
ডেভিড স্টোন

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

31

ব্যক্তিগত উত্তরাধিকারের প্রথাগত ব্যবহার হ'ল সম্পর্কের ক্ষেত্রে "প্রয়োগ করা" (এই শব্দটির জন্য স্কট মেয়ার্সের 'কার্যকর সি ++' কে ধন্যবাদ)। অন্য কথায়, উত্তরাধিকার সূত্রে প্রাপ্ত শ্রেণীর বাহ্যিক ইন্টারফেসের উত্তরাধিকারসূত্রে প্রাপ্ত শ্রেণীর সাথে কোনও (দৃশ্যমান) সম্পর্ক নেই, তবে এটি এর কার্যকারিতা বাস্তবায়নের জন্য এটি অভ্যন্তরীণভাবে ব্যবহার করে।


6
এটি এক্ষেত্রে ব্যবহৃত হওয়ার কারণগুলির একটি উল্লেখ করার মতো হতে পারে: এটি খালি বেস শ্রেণীর অপ্টিমাইজেশান সম্পাদন করতে দেয়, যা যদি ক্লাসটি বেস বর্গের পরিবর্তে সদস্য হত তবে ঘটবে না।
jalf

2
এর মূল ব্যবহার হ'ল জায়গাগুলির ব্যবহার হ্রাস করা যেখানে এটি সত্যই গুরুত্বপূর্ণ, যেমন নীতি নিয়ন্ত্রিত স্ট্রিং ক্লাসে বা সংক্ষেপিত জোড়ায়। প্রকৃতপক্ষে, উত্সাহিত :: সংকোচিত_জড়িটি সুরক্ষিত উত্তরাধিকার ব্যবহার করেছে।
জোহানেস স্কাউব -

জাল্ফ: আরে, আমি বুঝতে পারিনি আমি ভেবেছিলাম যখন আপনার কোনও শ্রেণীর সুরক্ষিত সদস্যদের অ্যাক্সেসের প্রয়োজন হয় তখন ননপাবলিক উত্তরাধিকার হ্যাক হিসাবে ব্যবহৃত হত। আমি ভাবছি যদিও কম্পোজিশনটি ব্যবহার করার সময় কোনও খালি বস্তু কেন কোনও স্থান গ্রহণ করবে। সম্ভবত সর্বজনীন ঠিকানাযোগ্যতার জন্য ...

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

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

23

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

উদাহরণ স্বরূপ:

class FooInterface
{
public:
    virtual void DoSomething() = 0;
};

class FooUser
{
public:
    bool RegisterFooInterface(FooInterface* aInterface);
};

class FooImplementer : private FooInterface
{
public:
    explicit FooImplementer(FooUser& aUser)
    {
        aUser.RegisterFooInterface(this);
    }
private:
    virtual void DoSomething() { ... }
};

সুতরাং FooUser ক্লাস FooImplementer এর ব্যক্তিগত পদ্ধতিগুলি FooInterface ইন্টারফেসের মাধ্যমে কল করতে পারে, অন্য অন্যান্য বাহ্যিক শ্রেণিগুলি এটি পারে না। ইন্টারফেস হিসাবে সংজ্ঞায়িত নির্দিষ্ট কলব্যাকগুলি পরিচালনা করার জন্য এটি দুর্দান্ত প্যাটার্ন।


1
প্রকৃতপক্ষে, ব্যক্তিগত উত্তরাধিকার হ'ল ব্যক্তিগত আইএস-এ।
কৌতূহলী

18

আমি মনে করি সি ++ এফএকিউ লাইটের সমালোচনা বিভাগটি হ'ল:

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

সন্দেহ হলে, আপনার ব্যক্তিগত উত্তরাধিকারের চেয়ে রচনাটি পছন্দ করা উচিত।


4

আমি ইন্টারফেসের (যেমন অ্যাবস্ট্রাক্ট ক্লাস) জন্য দরকারী বলে মনে করি যে আমি উত্তরাধিকার সূত্রে পাই যেখানে আমি অন্য কোডটি ইন্টারফেসটি স্পর্শ করতে চাই না (কেবল উত্তরাধিকারী শ্রেণি)।

[একটি উদাহরণে সম্পাদিত]

উপরে লিঙ্কিত উদাহরণ নিন । যে বলার অপেক্ষা রাখে না

[...] ক্লাস উইলমা আপনার নতুন ক্লাস ফ্রেডের সদস্য ফাংশন আহ্বান করতে হবে।

বলার অপেক্ষা রাখে না যে উইলমা ফ্রেডকে নির্দিষ্ট সদস্য ফাংশন আহ্বান করতে সক্ষম হতে বা তার পরিবর্তে এটি বলছে যে উইলমা একটি ইন্টারফেস । সুতরাং, উদাহরণ হিসাবে উল্লিখিত

ব্যক্তিগত উত্তরাধিকার মন্দ নয়; এটি বজায় রাখা আরও ব্যয়বহুল, যেহেতু এটির সম্ভাবনা বাড়িয়ে দেয় যে কেউ আপনার কোড ভঙ্গ করে এমন কিছু পরিবর্তন করবে।

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

[অন্য একটি উদাহরণে সম্পাদিত]

এই পৃষ্ঠাটি সংক্ষেপে বেসরকারী ইন্টারফেসগুলি (অন্য কোনও কোণ থেকে) নিয়ে আলোচনা করেছে।


সত্যিই দরকারী লাগছে না ... আপনি কি একটি উদাহরণ পোস্ট করতে পারেন

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

হ্যাঁ. আমার বোঝা উচিত, আমার বোঝার জন্য, 'ইন্টারফেস' শব্দটি জাভাতে বেশি ব্যবহৃত হয়। আমি যখন প্রথম শুনলাম তখন ভেবেছিলাম এটির আরও ভাল নাম দেওয়া যেতে পারে। যেহেতু, এই উদাহরণে আমাদের একটি ইন্টারফেস রয়েছে যা আমরা সাধারণত শব্দটি মনে করি না এমনভাবে ইন্টারফেস করে না।
পক্ষপাত

@ নূস: হ্যাঁ আমি মনে করি আপনার "উইলমা একটি ইন্টারফেস" বিবৃতিটি কিছুটা অস্পষ্ট, কারণ বেশিরভাগ লোকেরা এটি বোঝাতে চাইবে যে উইলমা এমন একটি ইন্টারফেস যা ফ্রেড কেবল উইলমার সাথে চুক্তির পরিবর্তে বিশ্বকে সরবরাহ করতে চায় ।
j_random_hacker

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

2

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

class BigClass;

struct SomeCollection
{
    iterator begin();
    iterator end();
};

class BigClass : private SomeCollection
{
    friend struct SomeCollection;
    SomeCollection &GetThings() { return *this; }
};

তারপরে যদি সাম্য সংগ্রহের বিগক্লাস অ্যাক্সেসের প্রয়োজন হয় তবে তা পারে static_cast<BigClass *>(this)। কোনও অতিরিক্ত ডেটা সদস্য স্থান নেওয়ার দরকার নেই।


ফরওয়ার্ড ঘোষণার কোন দরকার নেই BigClassএই উদাহরণে কি আছে? আমি এটি আকর্ষণীয় মনে করি, কিন্তু এটি আমার মুখে হ্যাকিশের চিৎকার করে।
থমাস এডিং

2

আমি ব্যক্তিগত উত্তরাধিকারের জন্য একটি দুর্দান্ত অ্যাপ্লিকেশন পেয়েছি, যদিও এর সীমিত ব্যবহার রয়েছে।

সমস্যা সমাধান

ধরুন আপনাকে নিম্নলিখিত সিপিআই দেওয়া হয়েছে:

#ifdef __cplusplus
extern "C" {
#endif

    typedef struct
    {
        /* raw owning pointer, it's C after all */
        char const * name;

        /* more variables that need resources
         * ...
         */
    } Widget;

    Widget const * loadWidget();

    void freeWidget(Widget const * widget);

#ifdef __cplusplus
} // end of extern "C"
#endif

এখন আপনার কাজ হ'ল সি ++ ব্যবহার করে এই এপিআই প্রয়োগ করা।

সি-ইশ পদ্ধতির

অবশ্যই আমরা এর মতো সি-ইশ বাস্তবায়ন স্টাইল বেছে নিতে পারি:

Widget const * loadWidget()
{
    auto result = std::make_unique<Widget>();
    result->name = strdup("The Widget name");
    // More similar assignments here
    return result.release();
}

void freeWidget(Widget const * const widget)
{
    free(result->name);
    // More similar manual freeing of resources
    delete widget;
}

তবে কয়েকটি অসুবিধা রয়েছে:

  • ম্যানুয়াল রিসোর্স (যেমন মেমরি) পরিচালনা
  • structভুল সেট আপ করা সহজ
  • সম্পদকে মুক্ত করার সময় ভুলে যাওয়া সহজ struct
  • এটি সি-ইশ

সি ++ অ্যাপ্রোচ

আমাদের সি ++ ব্যবহার করার অনুমতি দেওয়া হচ্ছে, তবে এর সম্পূর্ণ শক্তি কেন ব্যবহার করবেন না?

স্বয়ংক্রিয় সংস্থান পরিচালনার উপস্থাপন করা হচ্ছে

উপরের সমস্যাগুলি মূলত সমস্ত ম্যানুয়াল রিসোর্স ম্যানেজমেন্টের সাথে আবদ্ধ। যে সমাধানটি মনে আসে তা হ'ল উত্তরাধিকার সূত্রে Widgetপ্রাপ্ত WidgetImplএবং প্রতিটি ভেরিয়েবলের জন্য উত্পন্ন শ্রেণিতে একটি উত্স পরিচালনার উদাহরণ যুক্ত করা :

class WidgetImpl : public Widget
{
public:
    // Added bonus, Widget's members get default initialized
    WidgetImpl()
        : Widget()
    {}

    void setName(std::string newName)
    {
        m_nameResource = std::move(newName);
        name = m_nameResource.c_str();
    }

    // More similar setters to follow

private:
    std::string m_nameResource;
};

এটি নিম্নলিখিতগুলিতে বাস্তবায়নকে সহজতর করে:

Widget const * loadWidget()
{
    auto result = std::make_unique<WidgetImpl>();
    result->setName("The Widget name");
    // More similar setters here
    return result.release();
}

void freeWidget(Widget const * const widget)
{
    // No virtual destructor in the base class, thus static_cast must be used
    delete static_cast<WidgetImpl const *>(widget);
}

এটির মতো আমরা উপরের সমস্ত সমস্যার প্রতিকার করেছি। তবে একটি ক্লায়েন্ট এখনও সেটারগুলি সম্পর্কে ভুলে যেতে WidgetImplপারে এবং Widgetসরাসরি সদস্যদের অর্পণ করতে পারে ।

ব্যক্তিগত উত্তরাধিকার মঞ্চে প্রবেশ করে

Widgetসদস্যদের encapsulate করতে আমরা ব্যক্তিগত উত্তরাধিকার ব্যবহার করি। দু: খজনকভাবে এখন আমাদের উভয় শ্রেণির মধ্যে কাস্ট করতে দুটি অতিরিক্ত ফাংশন প্রয়োজন:

class WidgetImpl : private Widget
{
public:
    WidgetImpl()
        : Widget()
    {}

    void setName(std::string newName)
    {
        m_nameResource = std::move(newName);
        name = m_nameResource.c_str();
    }

    // More similar setters to follow

    Widget const * toWidget() const
    {
        return static_cast<Widget const *>(this);
    }

    static void deleteWidget(Widget const * const widget)
    {
        delete static_cast<WidgetImpl const *>(widget);
    }

private:
    std::string m_nameResource;
};

এটি নিম্নলিখিত রূপান্তরগুলি প্রয়োজনীয় করে তোলে:

Widget const * loadWidget()
{
    auto widgetImpl = std::make_unique<WidgetImpl>();
    widgetImpl->setName("The Widget name");
    // More similar setters here
    auto const result = widgetImpl->toWidget();
    widgetImpl.release();
    return result;
}

void freeWidget(Widget const * const widget)
{
    WidgetImpl::deleteWidget(widget);
}

এই সমাধানটি সমস্ত সমস্যার সমাধান করে। কোনও ম্যানুয়াল মেমরি ম্যানেজমেন্ট নেই এবং Widgetসুন্দরভাবে এনপ্যাপসুলেটেড রয়েছে যাতে WidgetImplকোনও পাবলিক ডেটা সদস্য না থাকে। এটি কার্যকরভাবে সঠিকভাবে ব্যবহার করা সহজ এবং ভুল ব্যবহার করা সহজ (অসম্ভব?)।

কোড স্নিপেটগুলি কলিরুতে একটি সংকলন উদাহরণ তৈরি করে


1

যদি উত্পন্ন শ্রেণি - কোডটি পুনরায় ব্যবহার করতে হবে এবং - আপনি বেস শ্রেণিটি পরিবর্তন করতে পারবেন না এবং - লকের নিচে বেসের সদস্যদের ব্যবহার করে এর পদ্ধতিগুলি রক্ষা করছেন।

তারপরে আপনার ব্যক্তিগত উত্তরাধিকার ব্যবহার করা উচিত, অন্যথায় আপনার উত্পন্ন শ্রেণীর মাধ্যমে রফতানি করা আনলক করা বেস পদ্ধতিগুলির ঝুঁকি রয়েছে।


1

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

তবে আপনি ঠিক বলেছেন, এর বাস্তব জগতের কোনও উদাহরণ নেই।


0

সম্পর্ক "একটি" না হলে ব্যক্তিগত উত্তরাধিকার ব্যবহার করা হবে, তবে নতুন শ্রেণিটি "বিদ্যমান শ্রেণীর মেয়াদে" প্রয়োগ করা যেতে পারে বা নতুন শ্রেণি "বিদ্যমান শ্রেণীর মতো" কাজ করা যেতে পারে।

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

একটি বর্গক্ষেত্র "is-a" আয়তক্ষেত্র (গাণিতিক) তবে একটি স্কোয়ার একটি আয়তক্ষেত্র নয় (আচরণগতভাবে)। ফলস্বরূপ, বর্ণনাকে ভুল বোঝাবুঝির ঝুঁকিতে পরিণত করার জন্য আমরা "is-a" এর পরিবর্তে "" work-like-a "(বা, যদি আপনি পছন্দ করেন" "ব্যবহারযোগ্য-তে-এ") বলতে পছন্দ করি।


0

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

struct QuadraticEquationState {
   const double a;
   const double b;
   const double c;

   // named ctors so aggregate construction is available,
   // which is the default usage pattern
   // add your favourite ctors - throwing, try, cps
   static QuadraticEquationState read(std::istream& is);
   static std::optional<QuadraticEquationState> try_read(std::istream& is);

   template<typename Then, typename Else>
   static std::common_type<
             decltype(std::declval<Then>()(std::declval<QuadraticEquationState>()),
             decltype(std::declval<Else>()())>::type // this is just then(qes) or els(qes)
   if_read(std::istream& is, Then then, Else els);
};

// this works with QuadraticEquation as well by default
std::ostream& operator<<(std::ostream& os, const QuadraticEquationState& qes);

// no operator>> as we're const correct.
// we _might_ (not necessarily want) operator>> for optional<qes>
std::istream& operator>>(std::istream& is, std::optional<QuadraticEquationState>);

struct QuadraticEquationCache {
   mutable std::optional<double> determinant_cache;
   mutable std::optional<double> x1_cache;
   mutable std::optional<double> x2_cache;
   mutable std::optional<double> sum_of_x12_cache;
};

class QuadraticEquation : public QuadraticEquationState, // private if base is non-const
                          private QuadraticEquationCache {
public:
   QuadraticEquation(QuadraticEquationState); // in general, might throw
   QuadraticEquation(const double a, const double b, const double c);
   QuadraticEquation(const std::string& str);
   QuadraticEquation(const ExpressionTree& str); // might throw
}

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

ব্যক্তিগত উত্তরাধিকার প্রায় সর্বদা সদস্য দ্বারা মডেল করা যেতে পারে (প্রয়োজনে বেসের রেফারেন্স সঞ্চয় করে)। এইভাবে মডেল করার পক্ষে এটি সর্বদা মূল্যবান নয়; কখনও কখনও উত্তরাধিকার সবচেয়ে দক্ষ প্রতিনিধিত্ব হয়।


0

আপনার যদি std::ostreamকিছু ছোট পরিবর্তন (যেমন এই প্রশ্নের মতো ) থাকে তবে আপনার প্রয়োজন হতে পারে

  1. একটি ক্লাস তৈরি করুন MyStreambufযা উত্স থেকে এসেছে std::streambufএবং সেখানে পরিবর্তনগুলি প্রয়োগ করে
  2. এমন একটি ক্লাস তৈরি করুন MyOStreamযা থেকে উদ্ভূত std::ostreamহয় এবং এটির উদাহরণটি শুরু করে এবং পরিচালনা করে MyStreambufএবং পয়েন্টারটিকে সেই কনস্ট্রাক্টরের কাছে দেয়std::ostream

প্রথম ধারণাটি ক্লাসে MyStreamডেটা সদস্য হিসাবে উদাহরণ যুক্ত করা হতে পারে MyOStream:

class MyOStream : public std::ostream
{
public:
    MyOStream()
        : std::basic_ostream{ &m_buf }
        , m_buf{}
    {}

private:
    MyStreambuf m_buf;
};

তবে বেস ক্লাসগুলি কোনও ডেটা মেম্বার এর আগে তৈরি করা হয় যাতে আপনি একটি এখনও নির্মিত না হওয়া std::streambufউদাহরণটিতে পয়েন্টার দিয়ে std::ostreamযাচ্ছেন যা অবধারিত আচরণ।

উপরোক্ত প্রশ্নের উত্তর বেনের উত্তরটিতে সমাধানটির প্রস্তাব দেওয়া হয়েছে , প্রথমে স্ট্রিম বাফার থেকে প্রথমে উত্তোলন করুন, তারপরে প্রবাহ থেকে এবং তারপরে স্ট্রিমটি আরম্ভ করুন this:

class MyOStream : public MyStreamBuf, public std::ostream
{
public:
    MyOStream()
        : MyStreamBuf{}
        , basic_ostream{ this }
    {}
};

তবে ফলস্বরূপ শ্রেণিটি std::streambufউদাহরণ হিসাবে ব্যবহৃত হতে পারে যা সাধারণত অনাকাঙ্ক্ষিত। ব্যক্তিগত উত্তরাধিকারে স্যুইচ করা এই সমস্যার সমাধান করে:

class MyOStream : private MyStreamBuf, public std::ostream
{
public:
    MyOStream()
        : MyStreamBuf{}
        , basic_ostream{ this }
    {}
};

-1

কেবল সি ++ এর বৈশিষ্ট্য থাকার কারণে, এটি দরকারী নয় বা এটি ব্যবহার করা উচিত।

আমি বলব যে আপনি এটি ব্যবহার করা উচিত নয়।

আপনি যদি যাইহোক এটি ব্যবহার করে থাকেন তবে ভাল, আপনি মূলত এনক্যাপসুলেশন লঙ্ঘন করছেন এবং সংহতি হ্রাস করছেন। আপনি একটি শ্রেণিতে ডেটা রাখছেন, এবং এমন পদ্ধতিগুলি যুক্ত করছেন যা অন্য ক্লাসে ডেটা ম্যানিপুলেট করে।

অন্যান্য সি ++ বৈশিষ্ট্যগুলির মতো এটিও ক্লাস সিল করার মতো পার্শ্ব প্রতিক্রিয়া অর্জন করতে ব্যবহার করা যেতে পারে (ড্রিবিয়াসের উত্তরে উল্লিখিত), তবে এটি এটি একটি ভাল বৈশিষ্ট্য করে না।


আপনি কি কৌতুক করছেন? আমার সব কিছু -1! যাইহোক আমি এটি -100 ভোট
পেলেও

9
" আপনি মূলত এনক্যাপসুলেশন লঙ্ঘন করছেন " আপনি একটি উদাহরণ দিতে পারেন?
কৌতূহলী

1
এক শ্রেণির ডেটা এবং অন্য শব্দের আচরণে নমনীয়তা বৃদ্ধির মতো শোনা যায়, যেহেতু একাধিক আচরণের ক্লাস এবং ক্লায়েন্ট থাকতে পারে এবং তাদের যা পছন্দ করা উচিত তা বেছে নিতে পারে
makar
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.