বেস-ফর-অল-অবজেক্টস কেন সি ++ এ নিরুৎসাহিত করা হচ্ছে


76

স্ট্রাস্ট্রাপ বলেছে "তাত্ক্ষণিকভাবে আপনার সমস্ত ক্লাসের (একটি অবজেক্ট ক্লাস) এর জন্য একটি অনন্য বেস উদ্ভাবন করবেন না, (সি ++ প্রোগ্রামিং ভাষার চতুর্থ সংস্করণ, সেক 1.3.4)

বেস-ক্লাস-ফর-সব কিছুর জন্য সাধারণত একটি খারাপ ধারণা এবং এটি কখন তৈরি করা অর্থবোধ করে?


16
কারণ সি ++ জাভা নয় ... এবং আপনার এটি জোর করার চেষ্টা করা উচিত নয়।
একে_

10
স্ট্যাক ওভারফ্লোতে জিজ্ঞাসা করা হয়েছে: সি ++

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

2
চতুর নীতিটি "আপনার প্রয়োজন হবে না"। আপনি ইতিমধ্যে এর জন্য কোনও নির্দিষ্ট প্রয়োজনটি সনাক্ত না করে এটি করবেন না (যতক্ষণ না আপনি করেন)।
Jool

3
@ ক্যাক: আপনার মন্তব্যে "বেকুবের মতো" নিখোঁজ রয়েছে।
ডেড এমএমজি

উত্তর:


75

কারণ সেই বস্তুর কার্যকারিতার জন্য কী থাকবে? জাভাতে সমস্ত বেস শ্রেণি একটি টু স্ট্রিং, একটি হ্যাশকোড এবং সমতা এবং একটি মনিটর + শর্ত পরিবর্তনশীল।

  • টোস্ট্রিং কেবলমাত্র ডিবাগিংয়ের জন্য কার্যকর।

  • হ্যাশকোড কেবলমাত্র তখনই কার্যকর যখন আপনি এটিকে হ্যাশ-ভিত্তিক সংগ্রহের মধ্যে সংরক্ষণ করতে চান (সি ++ এর পছন্দটি হ্যাশিং ফাংশনটি পাত্রে টেমপ্লেট প্যারাম হিসাবে বা std::unordered_*সম্পূর্ণরূপে এড়ানো এবং পরিবর্তে std::vectorএবং সরল বিনা অর্ডারযুক্ত তালিকা ব্যবহার করা ) use

  • বেস অবজেক্ট ব্যতীত সমতা সংকলন সময়ে সহায়তা করা যেতে পারে, যদি তাদের একই ধরণের না থাকে তবে তারা সমান হতে পারে না। সি ++ এ এটি একটি সংকলন সময় ত্রুটি।

  • মনিটর এবং শর্তের পরিবর্তনশীল কেস ভিত্তিতে একটি ক্ষেত্রে স্পষ্টভাবে অন্তর্ভুক্ত করা হয়।

তবে যখন এটি করার প্রয়োজন আরও বেশি তখন ব্যবহারের ক্ষেত্রে রয়েছে।

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


7
আপনি সম্ভবত জাভাটির বেস ক্লাসের মূল কারণটি উল্লেখ করতে ভুলে গেছেন: জেনারিকের আগে, সংগ্রহের ক্লাসগুলি কাজ করতে বেস ক্লাসের প্রয়োজন ছিল। সবকিছু (অভ্যন্তরীণ স্টোরেজ, প্যারামিটার, রিটার্ন মান) টাইপ করা হয়েছিল Object
আলেকসান্দ্র ডাবিনস্কি

1
@ আলেকসান্ডারডুবিনস্কি: এবং জেনেরিকগুলি কেবল সিনট্যাকটিক চিনি যুক্ত করেছে, সত্যিকার অর্থেই কোনও পরিবর্তন হয়নি বরং পোলিশ।
উত্সাহক

4
আমি যুক্তি করব, হ্যাশ কোড, সাম্যতা এবং মনিটর সমর্থন জাভাতেও ডিজাইনের ভুল। কে বলেছিল যে সমস্ত জিনিসকে একটি লক তৈরি করা ভাল ধারণা ?!
usr

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

2
" হ্যাশকোড কেবলমাত্র তখনই কার্যকর যখন আপনি এটি হ্যাশ-ভিত্তিক সংগ্রহের মধ্যে সংরক্ষণ করতে চান (সি ++ এর মধ্যে পছন্দটি স্ট্যান্ড :: ভেক্টর এবং সরল নিরস্তর তালিকার জন্য) " "এর আসল কাউন্টারারেগমেন্টটি _hashCode'আলাদা ধারক ব্যবহার না করে' বরং নির্দেশিত যে C ++ এর std::unordered_mapপ্রয়োগ উপাদান সরবরাহ করার জন্য উপাদান শ্রেণি নিজেই প্রয়োজনের পরিবর্তে একটি টেম্পলেট যুক্তি ব্যবহার করে হ্যাশ করছে। এটি হ'ল সি ++ তে থাকা অন্য সমস্ত ভাল ধারক এবং সংস্থান-পরিচালকদের মতো এটি অ-অনুপ্রবেশকারী; এটি কারওর সাথে পরে কোনও প্রসঙ্গে তাদের প্রয়োজন পড়ার প্রয়োজনে এটি ফাংশন বা ডেটা সহ সমস্ত বস্তুকে দূষিত করে না ।
আন্ডারস্কোর_

100

কারণ সমস্ত বস্তুর দ্বারা ভাগ করা কোনও ফাংশন নেই। এই ইন্টারফেসে রাখার মতো কিছুই নেই যা সমস্ত শ্রেণীর জন্য অর্থবোধ তৈরি করে।


10
উত্তরের সরলতার জন্য +1, এটি সত্যই একমাত্র কারণ।
বিডব্লিউজি

7
আমার যে বৃহত কাঠামোর সাথে অভিজ্ঞতা আছে, সাধারণ বেস শ্রেণি << যা> প্রসঙ্গে পছন্দসই সিরিয়ালাইজেশন এবং প্রতিবিম্বের অবকাঠামো সরবরাহ করে। সাধরণ। এটি কেবলমাত্র ডেটা এবং মেটাডেটার সাথে একত্রে ক্রুটের একগুচ্ছ সিরিয়ালকরণের ফলস্বরূপ কার্যকর হয়েছিল এবং দক্ষতার জন্য ডেটা ফর্ম্যাটটিকে খুব বড় এবং জটিল করে তুলেছে।
dmckee

19
@ ডিএমকে: আমিও যুক্তি দিয়েছিলাম যে সিরিয়ালাইজেশন এবং প্রতিবিম্ব খুব কম বিশ্বব্যাপী দরকারী প্রয়োজন।
ডেড এমজি

16
@ ডিড এমজি: "তবে আপনি যদি সমস্ত কিছু সংরক্ষণ করার প্রয়োজন হয় তবে কি?"
ডিফোরে

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

25

আপনি যখনই বস্তুগুলির লম্বা উত্তরাধিকারের স্তরক্রম তৈরি করেন আপনি ফ্রেজিলে বেস ক্লাস (উইকিপিডিয়া।) এর সমস্যায় পড়েন to

অনেকগুলি পৃথক পৃথক (স্বতন্ত্র, বিচ্ছিন্ন) উত্তরাধিকারের শ্রেণিবদ্ধতা এই সমস্যাটিতে যাওয়ার সম্ভাবনা হ্রাস করে।

আপনার সমস্ত বস্তুকে একটি একক হৈমন্তিক উত্তরাধিকারের স্তরক্রমের অংশ বানানো কার্যত গ্যারান্টি দেয় যে আপনি এই সমস্যার মধ্যে চলে যাচ্ছেন।


6
যখন বেস ক্লাসটি (জাভা "java.lang.Object" তে) এমন কোনও পদ্ধতি না থাকে যা অন্য পদ্ধতিগুলিকে কল করে ফ্রেজিলে বেস ক্লাসের সমস্যা দেখা দিতে পারে না।
মার্টিন রোজনৌ

3
একটি শক্তিশালী দরকারী বেস ক্লাস যে হবে!
মাইক নাকিস

9
@ মার্টিনরোসেনৌ ... যেমন আপনি মাস্টার বেস ক্লাসের প্রয়োজন ছাড়াই সি ++ তে করতে পারেন!
gbjbaanb

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

4
@ ডিভেরাসড্রালো: ফাংশনের নামটি অপ্রাসঙ্গিক। একটি বাক্য গঠন চিত্র করুন cout.print(x).print(0.5).print("Bye\n")- এটি কব্জ করে না operator<<
এমসাল্টার

24

কারণ:

  1. আপনি যা ব্যবহার করেন না তার জন্য আপনাকে অর্থ প্রদান করা উচিত নয়।
  2. এই ফাংশনগুলি একটি রেফারেন্স-ভিত্তিক টাইপ সিস্টেমের চেয়ে মান ভিত্তিক টাইপ সিস্টেমে কম বোঝায়।

যে কোন ধরণের বাস্তবায়নvirtual ক্রিয়াকলাপ ভার্চুয়াল-টেবিল প্রবর্তন করা হয়, যার জন্য প্রতি-অবজেক্ট স্পেসের ওভারহেড প্রয়োজন যা অনেকগুলি (বেশিরভাগ?) পরিস্থিতিতে প্রয়োজনীয় বা পছন্দসই নয়।

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


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

সেই কাগজটি সম্পর্কে আরও কিছুটা আলোচনা ল্যাম্বডা -থ
ফিজ

একটি সাধারণ বেস বর্গ হচ্ছে এটা সম্ভব পরীক্ষা করতে হবে কোনো shared_ptr<Foo> যদি এটি একটি কিনা দেখতে shared_ptr<Bar>(অন্যান্য পয়েন্টার ধরনের সহ বা অনুরূপভাবে), এমনকি যদি Fooএবং Barসম্পর্কহীন শ্রেণীর যা একে অপরের সম্পর্কে কিছুই জানি না হয়। "কাঁচা পয়েন্টার" এর সাথে এই জাতীয় জিনিস ব্যবহার করা দরকার, ইতিহাস কীভাবে এই জাতীয় জিনিস ব্যবহার করা হয় তা ব্যয়বহুল, তবে যে জিনিসগুলি যেভাবেই heাল-সঞ্চিত হতে চলেছে, সংযুক্ত ব্যয়টি সর্বনিম্ন হবে।
সুপারক্যাট

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

16

একটি রুট অবজেক্ট থাকার কারণে আপনি কী করতে পারেন এবং সংকলকটি কি করতে পারে তা সীমাবদ্ধ করে দেয় না much

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

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

উত্তরাধিকার, বিশেষত একজাতীয় উত্তরাধিকারের ধরণের জাভা স্টাইলের বেস ক্লাসগুলি বোঝায়, ফ্রি-স্টোর ভিত্তিক "পয়েন্টার" বা "রেফারেন্স" প্রকারের প্রয়োজন। আপনার হ্যান্ডেল / পয়েন্টার / ডেটাতে রেফারেন্সটি ক্লাসের ইন্টারফেসে একটি পয়েন্টার ধারণ করে, এবং বহুতলিকভাবে অন্য কোনও উপস্থাপনা করতে পারে।

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

প্রায় সবসময় আপনি কলিং সাইটে হয়, বা কোডটি ব্যবহার করে যে কোনও কোডে "এটি একটি বস্তু" এর চেয়ে কোনও ধরণের সম্পর্কে আরও বেশি জানেন।

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

মনে করুন আপনার কাছে এমন কিছু লাইব্রেরি রয়েছে যেখানে আপনি চান সমস্ত কিছু সিরিয়ালযোগ্য হতে পারে। একটি পদ্ধতির একটি বেস শ্রেণি আছে:

struct serialization_friendly {
  virtual void write_to( my_buffer* ) const = 0;
  virtual void read_from( my_buffer const* ) = 0;
  virtual ~serialization_friendly() {}
};

এখন আপনার লেখার প্রতিটি বিট কোড হতে পারে serialization_friendly

void serialize( my_buffer* b, serialization_friendly const* x ) {
  if (x) x->write_to(b);
}

এ ব্যতীত std::vector, এখন আপনার প্রতিটি পাত্রে লেখার প্রয়োজন। এবং আপনি যে বিগনাম লাইব্রেরি থেকে প্রাপ্ত পূর্ণসংখ্যাগুলি পান না। এবং সেই ধরণের নয় আপনি লিখেছেন যে আপনি সিরিয়ালাইজেশন প্রয়োজন বলে মনে করেন নি। এবং না একটি tuple, বা একটি intবা একটি double, বা এstd::ptrdiff_t

আমরা অন্য পদ্ধতি গ্রহণ:

void write_to( my_buffer* b, int x ) {
  b->write_integer(x);
}    
template<class T,
  class=std::enable_if_t< void_t<
    std::declval<T const*>()->write_to( std::declval<my_buffer*>()
  > >
>
void write_to( my_buffer* b, T const* x ) {
  if (x) x->write_to(b);
}
template<class T>
void serialize( my_buffer* b, T const& t ) {
  write_to( b, t );
}

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

এমনকি আমরা মুছে ফেলা কোডের প্রকারটিও লিখতে পারি:

namespace details {
  struct can_serialize_pimpl {
    virtual void write_to( my_buffer* ) const = 0;
    virtual void read_from( my_buffer const* ) = 0;
    virtual ~can_serialize_pimpl() {}
  };
}
struct can_serialize {
  void write_to( my_buffer* b ) const { pImpl->write_to(b); }
  void read_from( my_buffer const* b ) { pImpl->read_from(b); }
  std::unique_ptr<details::can_serialize_pimpl> pImpl;
  template<class T> can_serialize(T&&);
};
namespace details { 
  template<class T>
  struct can_serialize : can_serialize_pimpl {
    std::decay_t<T>* t;
    void write_to( my_buffer*b ) const final override {
      serialize( b, std::forward<T>(*t) );
    }
    void read_from( my_buffer const* ) final override {
      deserialize( b, std::forward<T>(*t) );
    }
    can_serialize(T&& in):t(&in) {}
  };
}
template<class T> can_serialize::can_serialize<T>(T&&t):pImpl(
  std::make_unique<details::can_serialize<T>>( std::forward<T>(t) );
) {}

এবং এখন আমরা একটি স্বেচ্ছাসেবী টাইপ নিতে পারি এবং এটি একটি can_serializeইন্টারফেসে অটো-বক্স করতে পারি যা আপনাকে serializeভার্চুয়াল ইন্টারফেসের মাধ্যমে পরবর্তী সময়ে প্রার্থনা করতে দেয় ।

তাই:

void writer_thingy( can_serialize s );

এর পরিবর্তে সিরিয়ালাইজ করতে পারে এমন কোনও কিছু এমন ফাংশন

void writer_thingy( serialization_friendly const* s );

এবং প্রথমটি, দ্বিতীয়টির থেকে ভিন্ন, এটি পরিচালনা করতে পারে int,std::vector<std::vector<Bob>> স্বয়ংক্রিয়ভাবে।

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

আরও কী, আমরা এখন std::vector<T>ওভাররাইড করে প্রথম শ্রেণির নাগরিক হিসাবে সিরিয়ালীকরণযোগ্য করতে পারি write_to( my_buffer*, std::vector<T> const& )- সেই ওভারলোডের সাহায্যে এটি একটিতে চলে যেতে পারে can_serializeএবং এর সিরিয়ালজ্যাবিলিটটি std::vectorএকটি ভিটিবেলে সংরক্ষণ করা হয় এবং এর মাধ্যমে অ্যাক্সেস করা যায় .write_to

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

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


8

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


1
হীরা সমস্যার একটি সমাধান হ'ল সমস্ত ধরণের যা অবিচলিত এক ভিত্তিক ধরণের একাধিক পাথের মাধ্যমে সেই ভিত্তির সমস্ত ভার্চুয়াল সদস্যকে ওভাররাইড করে; যদি প্রথম থেকেই ভাষায় একটি সাধারণ বেস টাইপ তৈরি করা হত, তবে একটি সংকলক বৈধ (যদিও চিত্তাকর্ষক নয়) ডিফল্ট বাস্তবায়নগুলি স্বয়ংক্রিয়ভাবে তৈরি করতে পারে।
সুপারক্যাট

5

আসলে মাইক্রোসফ্টস প্রারম্ভিক সি ++ কম্পাইলার এবং লাইব্রেরিগুলিতে (আমি ভিজ্যুয়াল সি ++, 16 বিট সম্পর্কে জানি) নামের একটি শ্রেণি ছিল CObject

তবে আপনাকে জানতে হবে যে সেই সময়ে "টেমপ্লেটগুলি" এই সাধারণ সি ++ সংকলক দ্বারা সমর্থিত ছিল না সুতরাং এর মতো ক্লাসগুলি std::vector<class T>সম্ভব ছিল না। পরিবর্তে একটি "ভেক্টর" বাস্তবায়ন কেবল এক ধরণের শ্রেণি পরিচালনা করতে পারে তাই std::vector<CObject>আজকের তুলনায় এমন একটি শ্রেণি ছিল । কারণ CObjectপ্রায় সব ক্লাসের বেস ক্লাস ছিল (দুর্ভাগ্যক্রমে নয় CString- stringআধুনিক কম্পাইলারগুলির সমতুল্য ) আপনি প্রায় সব ধরণের অবজেক্ট স্টোর করার জন্য এই ক্লাসটি ব্যবহার করতে পারেন।

কারণ আধুনিক সংকলকগণ টেমপ্লেটগুলি সমর্থন করে "জেনেরিক বেস শ্রেণি" এর ব্যবহারের ক্ষেত্রে আর দেওয়া হয় না।

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


3
এটা কি এমএফসি? [মন্তব্য প্যাডিং]
immibis

3
এটি আসলে এমএফসি। ওও ডিজাইনের একটি জ্বলজ্বল বাতিঘর যা বিশ্বকে দেখিয়েছিল কীভাবে জিনিসগুলি করা উচিত। ওহ, অপেক্ষা করুন ...
gbjbaanb

4
এমজিএফসিটির TObjectঅস্তিত্বের আগে @gbjbaanb টার্বো পাস্কাল এবং টার্বো সি ++ এর নিজস্ব নিজস্ব বৈশিষ্ট্য ছিল। ডিজাইনের সেই অংশটির জন্য মাইক্রোসফ্টকে দোষারোপ করবেন না, মনে হয়েছিল সেই সময়ের প্রায় প্রত্যেকের কাছে এটি একটি ভাল ধারণা বলে মনে হয়েছিল।
এইচডিভি

টেমপ্লেটগুলির আগেও, সি ++ এ ছোট্ট লেখার চেষ্টা করার ফলে ভয়াবহ ফলাফল পাওয়া গেছে।
জেডিগোগস

@ এইচভিডি স্টিল, এমওএফসি বোরল্যান্ড উত্পাদিত যে কোনও কিছুর চেয়ে অবজেক্ট-ওরিয়েন্টেড ডিজাইনের অনেক খারাপ উদাহরণ example
জুলাই

5

আমি জাভা থেকে আসা অন্য একটি কারণ প্রস্তাব করতে যাচ্ছি।

কারণ আপনি কমপক্ষে বয়লার-প্লেট না করে সব কিছুর জন্য বেস-ক্লাস তৈরি করতে পারবেন না ।

আপনি নিজের ক্লাসে এটির সাথে পালাতে সক্ষম হতে পারেন - তবে আপনি সম্ভবত দেখতে পাবেন যে আপনি প্রচুর কোডের নকল করেছেন। উদাহরণস্বরূপ " std::vectorএটি প্রয়োগ না হওয়ায় IObjectআমি এখানে ব্যবহার করতে পারছি না - আমি আরও ভাল একটি নতুন উত্পন্ন উত্স তৈরি IVectorObjectকরতে পারি যা সঠিক কাজ করে ..."।

যখনই আপনি বিল্ট-ইনগুলি বা স্ট্যান্ডার্ড লাইব্রেরি ক্লাস বা অন্যান্য লাইব্রেরির ক্লাসগুলি নিয়ে কাজ করছেন তখনই এটি ঘটবে।

এখন যদি এটা ভাষা পাতাটা তুমি ভালো জিনিস দিয়ে শেষ চাই Integerএবং intবিভ্রান্তির জাভা যে বা ভাষা বাক্য গঠন করতে একটি বৃহৎ পরিবর্তন। (মনে মনে আপনার মনে হয় অন্য কিছু ভাষাগুলি প্রতিটি প্রকারে এটি তৈরির সাথে একটি দুর্দান্ত কাজ করেছে - রুবি আরও ভাল উদাহরণ বলে মনে হয়))

এছাড়াও নোট করুন যে যদি আপনার বেস ক্লাসটি রান-টাইম পলিমারফিক হয় না (যেমন ভার্চুয়াল ফাংশনগুলি ব্যবহার করে) তবে আপনি কাঠামোর মতো বৈশিষ্ট্য ব্যবহার করে একই সুবিধা পেতে পারেন।

উদাহরণস্বরূপ আপনার পরিবর্তে .toString()নিম্নলিখিতগুলি থাকতে পারে: (দ্রষ্টব্য: আমি জানি আপনি বিদ্যমান লাইব্রেরি ইত্যাদির সাহায্যে এই সুন্দর কাজটি করতে পারেন, এটির একটি উদাহরণস্বরূপ উদাহরণ))

template<typename T>
struct ToStringTrait;

template<typename T> 
std::string toString(const T & t) {
  return ToStringTrait<T>::toString(t);
}

template<>
struct ToStringTrait<int> {
  std::string toString(int v) {
    return itoa(v);
  }
}

template<typename T>
struct ToStringTrait<std::vector<T>> {
  std::string toString(const std::vector<T> &v) {
    std::stringstream ss;
    ss<<"{";
    for(int i=0; i<v.size(); ++i) {
      ss<<toString(v[i]);
    }
    ss<<"}";
    return ss.str();
  }
}

3

যুক্তিযুক্তভাবে "অকার্যকর" একটি সার্বজনীন বেস শ্রেণির ভূমিকা অনেকগুলি পূরণ করে। আপনি যে কোনও পয়েন্টার কাস্ট করতে পারেন void*। তারপরে আপনি এই পয়েন্টারগুলির সাথে তুলনা করতে পারেন। আপনি static_castমূল ক্লাসে ফিরে যেতে পারেন ।

তবে কি আপনি করতে পারবেন না কি সঙ্গে voidআপনি করতে পারেন Objectব্যবহার RTTI আপনি কি সত্যিই আছে বস্তুর কি ধরনের চিন্তা হয়। এটি চূড়ান্তভাবে নীচে যে সি ++ তে সমস্ত বস্তুর আরটিটিআই নেই এবং প্রকৃতপক্ষে শূন্য-প্রস্থের অবজেক্টগুলি থাকা সম্ভব possible


1
কেবল শূন্য-প্রস্থের বেসক্লাস সাবওবজেক্টগুলি, সাধারণগুলি নয়।
উত্সর্গকারীর

@ ডেডুপ্লিকেটর আপডেটের মাধ্যমে, সি ++ 17 যোগ করে [[no_unique_address]], যা সংকলকরা সদস্য সাবওবজেক্টগুলিকে শূন্য প্রস্থ দিতে ব্যবহার করতে পারেন।
আন্ডারস্কোর_ইড

1
@ আসরে_আর_ আপনার মানে সি ++ ২০ এর জন্য পরিকল্পনা করা হয়েছে, সংস্থাপকটিকে [[no_unique_address]]ইবিও সদস্য-ভেরিয়েবলগুলিতে অনুমতি দেবে।
উত্সাহক ২

@ ডেডুপ্লিকেটর ওফস, হ্যাঁ আমি ইতিমধ্যে সি ++ 17 ব্যবহার শুরু করেছি, তবে আমার ধারণা আমি এখনও মনে করি এটি সত্যিকারের চেয়ে আরও বেশি কাটছে!
আন্ডারস্কোর_ইড

2

জাভা এমন নকশা দর্শন নিয়ে যায় যা অপরিজ্ঞাত আচরণের অস্তিত্ব থাকতে পারে না । কোড যেমন:

Cat felix = GetCat();
Woofer Rover = (Woofer)felix;
Rover.woof();

সেই প্রয়োগকারীর ইন্টারফেসের felixএকটি উপপ্রকার রয়েছে কিনা তা পরীক্ষা করবে ; যদি এটি হয় তবে এটি castালাই সম্পাদন করবে এবং প্রার্থনা করবে এবং যদি তা না করে তবে এটি ব্যতিক্রম ছুঁড়ে দেবে। কোডের আচরণটি প্রয়োগ বা না করাকে পুরোপুরি সংজ্ঞায়িত করা হয়CatWooferwoof()felixWoofer

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

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

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

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

অভিযোজ্য বস্তু

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


এই কাস্টটি সি ++ , জাভা এবং সি # তে সংকলনের সময় ব্যর্থ হয় ।
মিলেনিয়ামব্যাগ

1
@ মিলিলেনিম্বুগ: যদি Wooferএকটি ইন্টারফেস হয় এবং Catউত্তরাধিকারসূত্রে হয় তবে theালাই বৈধ হবে কারণ সেখানে উপস্থিত হতে পারে (যদি এখন না হয়, সম্ভবত ভবিষ্যতে) WoofingCatযা উত্তরাধিকার সূত্রে প্রাপ্ত Catএবং প্রয়োগকারী Woofer। নোট করুন যে জাভা সংকলন / লিঙ্কিং মডেল এর অধীনে একটি তৈরির জন্য WoofingCatসোর্স কোড অ্যাক্সেসের প্রয়োজন হবে না Catবা নয় Woofer
সুপারক্যাট

3
সি ++ করেছেন dynamic_cast , যা সঠিকভাবে A থেকে নিক্ষেপ করার চেষ্টা হ্যান্ডলগুলি Catএকটি থেকে Wooferএবং প্রশ্ন উত্তর দেব "আপনি টাইপ করতে পরিবর্তনীয় এক্স হয়"। সি ++ আপনাকে একটি নিক্ষেপকে জোর করার অনুমতি দেবে, আরে কারণ হতে পারে, সম্ভবত আপনি কী করছেন তা আপনি জানেন তবে এটি আপনাকে আপনাকে সহায়তা করবে যদি আপনি যা করতে চান তা সত্যই নয়।
রব কে

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

2
... সমস্ত বহুবৈজ্ঞানিক বস্তু একই লেআউট সহ কিছু তথ্য সঞ্চয় করে এবং সমস্ত এমন একটি আচরণকে সমর্থন করে যা অ-পলিমারফিক বস্তু দ্বারা সমর্থিত নয়; আমার মনে মনে, এর অর্থ তারা ব্যবহার করে যেন তারা একটি সাধারণ ভিত্তি থেকে প্রাপ্ত, ভাষার সংজ্ঞা যেমন পরিভাষা ব্যবহার করে কিনা।
সুপারক্যাট

1

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

এর পিছনে যুক্তিটি হ'ল এটি এম্বেডড সিস্টেমগুলির জন্য ভাষা এবং সি ++ কম্পাইলার এবং স্পেসগুলি সত্যই 10 বছর আগে ছিটে ছিল।

সমস্ত শ্রেণি এটি থেকে উত্তরাধিকার সূত্রে প্রাপ্ত নয়, কেবল কয়েকটি।

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