অন্য উত্তর কেন?
ঠিক আছে, এসও এবং বাইরের নিবন্ধগুলিতে অনেকগুলি পোস্টে বলা হয়েছে যে হীরক সমস্যাটি A
দু'জনের পরিবর্তে (প্রতিটি পিতামাতার জন্য একজন D
) একক উদাহরণ তৈরি করে এইভাবে অস্পষ্টতার সমাধান করে is যাইহোক, এটি আমাকে প্রক্রিয়াটির ব্যাপক বোঝাপড়া দেয় নি, আমি আরও অনেক প্রশ্নের মতো শেষ করেছি
- কী যদি
B
এবং C
উদাহরণস্বরূপ A
বিভিন্ন পরামিতি ( D::D(int x, int y): C(x), B(y) {}
) দিয়ে প্যারামেট্রাইজড কনস্ট্রাক্টরকে কল করার বিভিন্ন উদাহরণ তৈরি করার চেষ্টা করে ? কোন উদাহরণটি A
অংশ হিসাবে নির্বাচিত হবে D
?
- যদি আমি অ-ভার্চুয়াল উত্তরাধিকারের জন্য ব্যবহার করি
B
তবে ভার্চুয়ালটির জন্য C
? এটি একক উদাহরণস্বরূপ তৈরি জন্য যথেষ্ট A
মধ্যে D
?
- প্রতিরোধমূলক ব্যবস্থা হিসাবে এখন থেকে আমি কি সর্বদা ভার্চুয়াল উত্তরাধিকারকে প্রতিরোধমূলক ব্যবস্থা হিসাবে ব্যবহার করব যেহেতু এটি ছোটখাটো পারফরম্যান্স ব্যয় এবং অন্য কোনও ত্রুটিগুলি নিয়ে হীরা সমস্যাটি সমাধান করে?
কোড নমুনা চেষ্টা না করে আচরণের পূর্বাভাস দিতে সক্ষম না হওয়াই ধারণাটি বোঝা হয়নি। নীচে আমাকে ভার্চুয়াল উত্তরাধিকারের চারপাশে মাথা গুটিয়ে রাখতে সহায়তা করেছে।
ডাবল এ
প্রথমে ভার্চুয়াল উত্তরাধিকার ছাড়াই এই কোডটি দিয়ে শুরু করা যাক:
#include<iostream>
using namespace std;
class A {
public:
A() { cout << "A::A() "; }
A(int x) : m_x(x) { cout << "A::A(" << x << ") "; }
int getX() const { return m_x; }
private:
int m_x = 42;
};
class B : public A {
public:
B(int x):A(x) { cout << "B::B(" << x << ") "; }
};
class C : public A {
public:
C(int x):A(x) { cout << "C::C(" << x << ") "; }
};
class D : public C, public B {
public:
D(int x, int y): C(x), B(y) {
cout << "D::D(" << x << ", " << y << ") "; }
};
int main() {
cout << "Create b(2): " << endl;
B b(2); cout << endl << endl;
cout << "Create c(3): " << endl;
C c(3); cout << endl << endl;
cout << "Create d(2,3): " << endl;
D d(2, 3); cout << endl << endl;
cout << "d.B::getX() = " << d.B::getX() << endl;
cout << "d.C::getX() = " << d.C::getX() << endl;
}
আউটপুট মাধ্যমে যেতে দেয়। এক্সিকিউটিং প্রত্যাশিত হিসাবে B b(2);
তৈরি করে :A(2)
C c(3);
Create b(2):
A::A(2) B::B(2)
Create c(3):
A::A(3) C::C(3)
D d(2, 3);
উভয়ের প্রয়োজন B
এবং C
তাদের প্রত্যেকের নিজস্ব তৈরি করা A
, সুতরাং আমাদের দ্বিগুণ A
হয়েছে d
:
Create d(2,3):
A::A(2) C::C(2) A::A(3) B::B(3) D::D(2, 3)
যে জন্য কারণ d.getX()
কম্পাইলার চয়ন করতে পারবে না যা সংকলন ত্রুটি কারণ A
উদাহরণস্বরূপ এটা জন্য পদ্ধতি কল করা উচিত। তবুও নির্বাচিত অভিভাবক শ্রেণীর জন্য সরাসরি পদ্ধতিগুলি কল করা সম্ভব:
d.B::getX() = 3
d.C::getX() = 2
ভার্চুয়ালটি
এখন আসুন ভার্চুয়াল উত্তরাধিকার যোগ করুন। নিম্নলিখিত পরিবর্তনগুলির সাথে একই কোড নমুনা ব্যবহার:
class B : virtual public A
...
class C : virtual public A
...
cout << "d.getX() = " << d.getX() << endl;
cout << "d.A::getX() = " << d.A::getX() << endl;
...
তৈরি করতে লাফ দিন d
:
Create d(2,3):
A::A() C::C(2) B::B(3) D::D(2, 3)
আপনি দেখতে পাচ্ছেন, A
ডিফল্ট কনস্ট্রাক্টর B
এবং এর কনস্ট্রাক্টরগুলি থেকে পাস হওয়া পরামিতি উপেক্ষা করে তৈরি করা হয়েছে C
। অস্পষ্টতা চলে যাওয়ার সাথে সাথে সমস্ত কল getX()
একই মান ফেরত দেবে:
d.getX() = 42
d.A::getX() = 42
d.B::getX() = 42
d.C::getX() = 42
তবে আমরা যদি প্যারামেট্রাইজড কনস্ট্রাক্টরের জন্য কল করতে চাই A
? এটি নির্মাণকারীর কাছ থেকে স্পষ্টভাবে কল করে এটি করা যেতে পারে D
:
D(int x, int y, int z): A(x), C(y), B(z)
সাধারণত, শ্রেণিগুলি কেবল স্পষ্টভাবে সরাসরি পিতামাতার নির্মাতাদের ব্যবহার করতে পারে তবে ভার্চুয়াল উত্তরাধিকারের ক্ষেত্রে বর্জন রয়েছে। এই নিয়মটি আমার জন্য "ক্লিক করা" আবিষ্কার করে এবং ভার্চুয়াল ইন্টারফেসগুলি অনেক বোঝার জন্য সহায়তা করে:
কোডের class B: virtual A
অর্থ, উত্তরাধিকার সূত্রে প্রাপ্ত যে কোনও শ্রেণি B
এখন A
নিজেই তৈরি করার জন্য দায়বদ্ধ , যেহেতু B
এটি স্বয়ংক্রিয়ভাবে তা করবে না।
এই বিবৃতিটি মাথায় রেখে আমার কাছে থাকা সমস্ত প্রশ্নের উত্তর দেওয়া সহজ:
D
সৃষ্টির সময় এবং B
না C
প্যারামিটারগুলির জন্য দায়ী A
, এটি D
কেবলমাত্র সম্পূর্ণরূপে up
C
এতে তৈরি A
করার প্রতিনিধিত্ব করবে D
, কিন্তু ডায়মন্ডের সমস্যাটি ফিরিয়ে আনার B
নিজস্ব ঘটনা তৈরি করবেA
- সরাসরি সন্তানের পরিবর্তে নাতি-নাতনী শ্রেণিতে বেস শ্রেণির পরামিতিগুলি সংজ্ঞায়িত করা ভাল অনুশীলন নয়, তাই যখন হীরকের সমস্যা উপস্থিত থাকে তখন এটি সহ্য করা উচিত এবং এই ব্যবস্থাটি অনিবার্য।