একটি অস্ট্রিমের জন্য << অপারেটরটি কীভাবে সঠিকভাবে ওভারলোড করবেন?


237

আমি ম্যাট্রিক্স অপারেশনের জন্য সি ++ তে একটি ছোট ম্যাট্রিক্স লাইব্রেরি লিখছি। তবে আমার সংকলকটি অভিযোগ করে, যেখানে আগে তা হয়নি। এই কোডটি 6 মাসের জন্য একটি শেল্ফে রেখে গেছে এবং এর মধ্যে আমি আমার কম্পিউটারটিকে ডেবিয়ান এটচ থেকে লেনিতে উন্নীত করে (জি ++ (ডেবিয়ান 4.3.2-1.1) 4.3.2) তবে একই জি ++ সহ উবুন্টু সিস্টেমে আমার একই সমস্যা রয়েছে ।

আমার ম্যাট্রিক্স ক্লাসের প্রাসঙ্গিক অংশটি এখানে:

namespace Math
{
    class Matrix
    {
    public:

        [...]

        friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix);
    }
}

এবং "বাস্তবায়ন":

using namespace Math;

std::ostream& Matrix::operator <<(std::ostream& stream, const Matrix& matrix) {

    [...]

}

এটি সংকলক দ্বারা প্রদত্ত ত্রুটি:

ম্যাট্রিক্স সিপিপি: 459: ত্রুটি: 'এসটিডি :: অস্ট্রিউম অ্যান্ড ম্যাথ :: ম্যাট্রিক্স :: অপারেটর << (এসটিডি :: অস্ট্রিমে & কনস্ট ম্যাথ :: ম্যাট্রিক্স এবং)' অবশ্যই একটি যুক্তি গ্রহণ করবে

আমি এই ত্রুটিটি দিয়ে কিছুটা বিভ্রান্ত হয়ে পড়েছি, তবে তারপরে আবার আমার সি ++ Java মাসে প্রচুর জাভা করার পরে কিছুটা মরিচা হয়ে উঠেছে। :-)

উত্তর:


127

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


7
এবং আপনার এটি ম্যাথ নেমস্পেসের ভিতরেও ঘোষণা করা উচিত (কেবলমাত্র একটি নেমস্পেস ব্যবহার করে নয়)।
ডেভিড রদ্রিগেজ - 21

1
operator<<এর নামস্থানে কেন থাকতে হবে Math? দেখে মনে হচ্ছে এটি বিশ্বব্যাপী নেমস্পেসে থাকা উচিত। আমি সম্মত হই যে আমার সংকলকটি এটির নামস্থানে থাকতে চায় Math, তবে এটি আমার কাছে কোনও অর্থ দেয় না।
লাকাটা

দুঃখিত, তবে আমি কেন এখানে বন্ধু কীওয়ার্ড ব্যবহার করি তা দেখতে আমি ব্যর্থ হয়েছি? যখন ক্লাসে বন্ধু অপারেটরকে ওভাররাইড ঘোষণা করে, মনে হয় আমরা ম্যাট্রিক্স :: অপারেটর << (ostream & os, Const ম্যাট্রিক্স এবং এম) দিয়ে প্রয়োগ করতে পারি না। এর পরিবর্তে আমাদের কেবলমাত্র গ্লোবাল অপারেটর ওভাররাইড অপারেটর ব্যবহার করা প্রয়োজন << ostream & OS, Const ম্যাট্রিক্স & এম) তবে কেন এটি শ্রেণীর অভ্যন্তরে প্রথম স্থানে ঘোষণা করতে বিরক্ত করবেন?
প্যাট্রিক

139

অন্য একটি সম্ভাবনার কথা আপনাকে বলছি: আমি তার জন্য বন্ধুত্বের সংজ্ঞা ব্যবহার করতে চাই:

namespace Math
{
    class Matrix
    {
    public:

        [...]

        friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix) {
            [...]
        }
    };
}

ফাংশনটি স্বয়ংক্রিয়ভাবে আশেপাশের নেমস্পেসে লক্ষ্যবস্তু হয়ে যাবে Math(যদিও এর সংজ্ঞাটি class শ্রেণীর ক্ষেত্রের মধ্যে উপস্থিত হয়) তবে আপনি অপারেটরকে কল না করা না হলে << ম্যাট্রিক্স অবজেক্টের সাহায্যে আর্গুমেন্ট নির্ভর লুকআপ সেই অপারেটরের সংজ্ঞাটি সন্ধান করবে। এটি মাঝেমধ্যে অস্পষ্ট কলগুলিতে সহায়তা করতে পারে, কারণ এটি ম্যাট্রিক্স ব্যতীত অন্য কোনও যুক্তির জন্য অদৃশ্য। এর সংজ্ঞাটি লেখার সময়, আপনি সম্ভবত কিছু দীর্ঘ উপসর্গের সাথে নামটির যোগ্যতা না রেখে এবং যেমন টেমপ্লেট পরামিতি সরবরাহ না করে ম্যাট্রিক্সে এবং ম্যাট্রিক্সে নিজেই সংজ্ঞায়িত নামগুলি সরাসরি উল্লেখ করতে পারেন Math::Matrix<TypeA, N>


77

মেহরদাদ উত্তর যুক্ত করতে,

namespace Math
{
    class Matrix
    {
       public:

       [...]


    }   
    std::ostream& operator<< (std::ostream& stream, const Math::Matrix& matrix);
}

আপনার বাস্তবায়নে

std::ostream& operator<<(std::ostream& stream, 
                     const Math::Matrix& matrix) {
    matrix.print(stream); //assuming you define print for matrix 
    return stream;
 }

4
আমি বুঝতে পারছি না কেন এটি একটি ডাউন ভোট, এটি স্পষ্ট করে যে আপনি অপারেটরটিকে নামস্থানতে ঘোষণা করতে পারেন এমনকি বন্ধু হিসাবেও নয় এবং কীভাবে আপনি অপারেটরটিকে সম্ভবত ঘোষণা করতে পারেন।
কল

2
মেহরদাদ উত্তরের কোডের কোনও স্নিপেট ছিল না তাই আমি কেবলমাত্র নিজের সাথে নামস্থানে শ্রেণীর বাইরে রেখে কী কাজ করতে পারে তা যুক্ত করেছিলাম।
কল

আমি আপনার বিষয়টি বুঝতে পারি, আমি কেবল আপনার দ্বিতীয় স্নিপেটের দিকে চেয়েছিলাম। তবে এখন দেখছি আপনি অপারেটরটিকে ক্লাস থেকে বের করে নিয়ে এসেছেন। পরামর্শের জন্য ধন্যবাদ.
ম্যাথিয়াস ভ্যান ডার ভিলেস 24:30

7
এটি কেবল শ্রেণীর বাইরে নয়, তবে এটি ম্যাথ নেমস্পেসের ভিতরে সঠিকভাবে সংজ্ঞায়িত হয়েছে । এছাড়াও এটির অতিরিক্ত সুবিধা রয়েছে (সম্ভবত কোনও ম্যাট্রিক্সের জন্য নয়, তবে অন্যান্য শ্রেণীর সাথে) যে 'মুদ্রণ' ভার্চুয়াল হতে পারে এবং সুতরাং প্রিন্টিং উত্তরাধিকারের সবচেয়ে প্রাপ্ত স্তরের স্তরে ঘটবে।
ডেভিড রদ্রিগেজ - 21

68

ধরে নিই যে আমরা operator <<ক্লাস std::ostreamপরিচালনা করার জন্য প্রাপ্ত সমস্ত শ্রেণীর জন্য ওভারলোডিংয়ের কথা বলছি Matrix(এবং এর <<জন্য ওভারলোডিং নয়)Matrix ), এটি শিরোনামের ম্যাথ নেমস্পেসের বাইরে ওভারলোড ফাংশনটি ঘোষণা করার আরও বোধগম্য হয়।

কার্যকারিতা জনসাধারণের ইন্টারফেসের মাধ্যমে অর্জন করা সম্ভব না হলে কেবলমাত্র একটি ফাংশন ব্যবহার করুন।

Matrix.h

namespace Math { 
    class Matrix { 
        //...
    };  
}
std::ostream& operator<<(std::ostream&, const Math::Matrix&);

নোট করুন যে অপারেটর ওভারলোড নেমস্পেসের বাইরে ঘোষণা করা হয়েছে।

Matrix.cpp

using namespace Math;
using namespace std;

ostream& operator<< (ostream& os, const Matrix& obj) {
    os << obj.getXYZ() << obj.getABC() << '\n';
    return os;
}

অন্যদিকে, আপনার জমিদার ফাংশন যদি না কে বন্ধু অর্থাত ব্যক্তিগত এবং সুরক্ষিত সদস্যদের অ্যাক্সেস করা প্রয়োজন তৈরি করা প্রয়োজন।

math.h

namespace Math {
    class Matrix {
        public:
            friend std::ostream& operator<<(std::ostream&, const Matrix&);
    };
}

আপনাকে ফাংশন সংজ্ঞাটি কেবলমাত্র পরিবর্তে একটি নেমস্পেস ব্লক দিয়ে আবদ্ধ করতে হবে using namespace Math;

Matrix.cpp

using namespace Math;
using namespace std;

namespace Math {
    ostream& operator<<(ostream& os, const Matrix& obj) {
        os << obj.XYZ << obj.ABC << '\n';
        return os;
    }                 
}

38

সি ++ ১৪ এ আপনি যে কোনও অবজেক্টের টি :: প্রিন্ট (স্ট্যান্ড :: ওস্ট্রিমে &) কনস্টেট প্রিন্ট করতে নিম্নলিখিত টেম্পলেটটি ব্যবহার করতে পারেন; সদস্য।

template<class T>
auto operator<<(std::ostream& os, T const & t) -> decltype(t.print(os), os) 
{ 
    t.print(os); 
    return os; 
} 

সি ++ তে 20 টি ধারণা ব্যবহার করা যেতে পারে।

template<typename T>
concept Printable = requires(std::ostream& os, T const & t) {
    { t.print(os) };
};

template<Printable T>
std::ostream& operator<<(std::ostream& os, const T& t) { 
    t.print(os); 
    return os; 
} 

আকর্ষণীয় সমাধান! একটি প্রশ্ন - এই অপারেটরটি কোথায় ঘোষণা করা উচিত, যেমন বিশ্বব্যাপী? আমি ধরে নিলাম এটি সমস্ত ধরণের কাছে দৃশ্যমান হওয়া উচিত যা এটি সংক্ষেপে ব্যবহার করতে পারে?
বার্নি

@ বার্নি এটি ব্যবহার করে এমন ক্লাসগুলির সাথে এটি আপনার নিজের নামের সাথে থাকতে পারে।
কোয়ান্টিনুক

আপনি কি কেবল ফিরতে পারবেন না std::ostream&, যেহেতু এটি রিটার্নের ধরণ?
জিন-মিশেল সেলারিয়ার

5
@ জিন-মাইচেলসিলিয়ার ডিক্লাইপটি নিশ্চিত করে যে এই অপারেটরটি কেবলমাত্র যখন টি :: প্রিন্ট উপস্থিত থাকে তখনই ব্যবহৃত হয়। অন্যথায় এটি ফাংশন বডিটি সংকলন করার চেষ্টা করবে এবং সংকলনের ত্রুটি দেবে।
কোয়ান্টিনুক

ধারণাগুলি সংস্করণ যুক্ত হয়েছে, এখানে পরীক্ষিত হয়েছে Godbolt.org/z/u9fGbK
কোয়ান্টিন ইউকে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.