বিমূর্ত বেস ক্লাস এবং অনুলিপি নির্মাণ, থাম্বের নিয়ম


10

প্রায়শই সময় এটির ইন্টারফেসটি আলাদা করার জন্য একটি বিমূর্ত বেস শ্রেণি রাখা ভাল ধারণা।

সমস্যাটি হ'ল অনুলিপি নির্মাণ, আইএমএইচও, সি ++ এ ডিফল্টরূপে অনেকটা নষ্ট হয়ে গেছে, অনুলিপিটি অনুলিপি তৈরির সাথে তৈরি হয়েছে।

সুতরাং, যখন আপনি একটি বিমূর্ত বেস শ্রেণি এবং উত্পন্ন ক্লাসে কাঁচা পয়েন্টার পেয়েছেন তখন কী হবে?

class IAbstract
{
    ~IAbstract() = 0;
}

class Derived : public IAbstract
{
    char *theProblem;
    ...
}

IAbstract *a1 = new Derived();
IAbstract a2 = *a1;//???

এবং এখন আপনি পুরো শ্রেণিবিন্যাসের জন্য অনুলিপিটি পরিষ্কারভাবে অক্ষম করবেন? অনুলিপিটি কি ব্যক্তিগত হিসাবে ঘোষণা করবেন IAbstract?

অ্যাবস্ট্রাক্ট বেস ক্লাস সহ তিনটি বিধি আছে কি?


1
পয়েন্টারের পরিবর্তে রেফারেন্স ব্যবহার করুন :)
tp1

@ টিপি 1: বা কমপক্ষে কিছু স্মার্ট পয়েন্টার।
বেনজামিন ব্যানিয়ার

1
কখনও কখনও আপনাকে কেবল বিদ্যমান কোড দিয়ে কাজ করতে হবে ... আপনি তাত্ক্ষণিকভাবে সবকিছু পরিবর্তন করতে পারবেন না।
কোডার

আপনি কেন ডিফল্ট অনুলিপি নির্মাণকারী ভাঙা ভাবেন?
BЈовић

2
@ কোডার: গুগল স্টাইল গাইডটি জাঙ্কের একটি স্তূপ এবং কোনও সি ++ বিকাশের জন্য একেবারে সফলকাম।
ডেড এমজি

উত্তর:


6

একটি বিমূর্ত ক্লাসে অনুলিপি নির্মাণ বেশিরভাগ ক্ষেত্রেই ব্যক্তিগত করা উচিত, পাশাপাশি অ্যাসাইনমেন্ট অপারেটরও।

বিমূর্ত শ্রেণিগুলি সংজ্ঞা অনুসারে একটি বহুবর্ষীয় ধরণের হয়ে থাকে। সুতরাং আপনি জানেন না যে আপনার উদাহরণটি কতটা মেমরি ব্যবহার করছে এবং তাই এটি অনুলিপি করে বা নিরাপদে নির্ধারণ করতে পারে না। অনুশীলনে, আপনি কাটা ঝুঁকিপূর্ণ: /programming/274626/ কি-is-the-slicing-problem-in-c

পলিমারফিক টাইপ, সি ++ এ, অবশ্যই মান দ্বারা হেরফের করা উচিত নয়। আপনি এগুলি রেফারেন্স বা পয়েন্টার (বা কোনও স্মার্ট পয়েন্টার) দ্বারা ম্যানিপুলেট করুন।

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


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

3
সাধরণ। এটি একটি সমস্যাবিহীন- যে কেউ C ++ জানে সে এই ভুলটি করবে না। আরও গুরুত্বপূর্ণ বিষয়, আপনি কী করছেন তা যদি আপনি জানেন তবে মান অনুসারে বহুবর্ণের ধরণের হস্তক্ষেপ করার কোনও কারণ নেই। আপনি প্রযুক্তিগতভাবে পাতলা সম্ভাবনা নিয়ে মোট হাঁটু-ঝাঁকুনির প্রতিক্রিয়া শুরু করছেন। নাল পয়েন্টার একটি বড় সমস্যা are
ডেড এমজি

8

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


এবং যদি কোনও বিমূর্ততা -> ডেরিভড 1 -> ডেরিভড 2 শ্রেণিবিন্যাস এবং ডেরিভড 2 ডেরিভড 1 এ নির্ধারিত হয় তবে কী হবে? ভাষার এই অন্ধকার কোণগুলি এখনও আমাকে অবাক করে।
কোডার

@ কোডার: এটি সাধারণত পিইবিএসিএসি হিসাবে দেখা হয়। তবে, আরো সরাসরি, আপনি সবসময় একটি প্রাইভেট ডিক্লেয়ার পারে operator=(const Derived2&)মধ্যে Derived1
ডেড এমজি

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

2
এবং তার জন্য আপনার একটি পদক পাওয়া উচিত।
বিশ্ব প্রকৌশলী

2
@ কোডার: কার দ্বারা গালি দেওয়া? আপনি যা করতে পারেন তা হ'ল সঠিক কোডটি লেখা সহজ করে দেওয়া। যে প্রোগ্রামাররা সি ++ জানেন না তাদের বিরুদ্ধে রক্ষা করার চেষ্টা করা অর্থহীন।
কেভিন ক্লায়ান

2

কর্টর এবং অ্যাসাইনমেন্টটি ব্যক্তিগত করে (বা সেগুলিকে সি ++ এ মুছুন হিসাবে ঘোষণা করে) অনুলিপিটি অক্ষম করুন।

এখানে পয়েন্টটি যেখানে আপনাকে এটি করতে হবে। আপনার কোড সহ থাকার জন্য, আইএবস্ট্রাক্ট কোনও সমস্যা নয়। (মনে রাখবেন যে আপনি যা করেছেন তা করছেন, আপনি *a1 IAbstractসাবোবজেক্টটি a2 তে অর্পণ করেছেন , কোনও রেফারেন্স হারিয়েছেন ue Derivedভ্যালু অ্যাসাইনমেন্টটি বহুরূপী নয়)

বিষয়টি নিয়ে আসে Derived::theproblem। অন্যের মধ্যে ডেরিভড অনুলিপি করা আসলে এমন *theproblemডেটা ভাগ করতে পারে যা ভাগ করে নেওয়ার জন্য নকশাকৃত নাও হতে পারে (এমন দুটি উদাহরণ রয়েছে যা delete theproblemতাদের ধ্বংসকারীকে কল করতে পারে )।

যদি তা কেস হয় তবে Derivedএটি অবশ্যই অনুলিপিযোগ্য এবং অ্যাসাইয়েবল নয়। অবশ্যই, যদি আপনি অনুলিপিটি ব্যক্তিগতভাবে তৈরি করেন IAbstract, যেহেতু Derivedএটির জন্য ডিফল্ট অনুলিপি প্রয়োজন হয় তবে Derivedতা অনুলিপিযোগ্যও হবে না। তবে আপনি যদি অনুলিপি Derived::Derived(const Derived&)কল না করে নিজের নিজস্ব সংজ্ঞা দেন তবে আপনি IAbtractসেগুলি অনুলিপি করতে পারেন।

সমস্যাটি ডারাইভেডে রয়েছে এবং সমাধানটি অবশ্যই ডারাইভের মধ্যে থাকতে হবে: যদি এটি কেবলমাত্র পয়েন্টার বা রেফারেন্স দ্বারা অ্যাক্সেস করা একটি গতিশীল-কেবলমাত্র বস্তু হয় তবে এটি নিজেই প্রাপ্ত হওয়া উচিত

class Derived
{
    ...
    Derived(const Derived&) = delete;
    Derived& operator=(const Derived&) = delete;
};

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

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