operatörü << tam olarak bir argüman almalıdır


94

Ah

#include "logic.h"
...

class A
{
friend ostream& operator<<(ostream&, A&);
...
};

logic.cpp

#include "a.h"
...
ostream& logic::operator<<(ostream& os, A& a)
{
...
}
...

Derlediğimde diyor ki:

std :: ostream & logic :: operator << (std :: ostream &, A &) 'tam olarak bir argüman almalıdır.

Sorun nedir?

Yanıtlar:


132

Sorun, onu sınıfın içinde tanımlamanızdır.

a) ikinci argümanın örtük olduğu anlamına gelir ( this) ve

b) Yapmasını istediğiniz şeyi yapmayacak, yani genişletmeyecektir std::ostream.

Bunu ücretsiz bir işlev olarak tanımlamalısınız:

class A { /* ... */ };
std::ostream& operator<<(std::ostream&, const A& a);

9
Ayrıca bunu bir arkadaş işlevi olarak ilan eder ve bir üye işlevi olarak tanımlar.
asaelr

En.cppreference.com/w/cpp/language/operators adresinde belirtildiği gibi , "std :: istream & veya std :: ostream ve sol el argümanı olarak alan operatörün >> ve operatörün << aşırı yüklemeleri ekleme olarak bilinir ve ayıklama operatörleri. Kullanıcı tanımlı türü doğru argüman olarak aldıklarından (a @ b'de b), üye olmayanlar olarak uygulanmaları gerekir ".
Morteza

49

Bir arkadaş işlevi bir üye işlevi değildir, bu nedenle sorun şu ki operator<< arkadaşı olarakA :

 friend ostream& operator<<(ostream&, A&);

sonra onu sınıfın bir üye işlevi olarak tanımlamaya çalışın logic

 ostream& logic::operator<<(ostream& os, A& a)
          ^^^^^^^

logicBir sınıf mı yoksa ad alanı mı olduğu konusunda kafanız mı karıştı ?

Hata, operator<<iki bağımsız değişken alan bir üye tanımlamaya çalıştığınız içindir , yani örtük thisparametre dahil üç bağımsız değişken alır . Operatör yalnızca iki argüman alabilir, böylece a << biki argüman yazdığınızdaa ve olur b.

Üye olmayan bir işlev ostream& operator<<(ostream&, const A&)olarak tanımlamak istiyorsunuz , bu sınıfla hiçbir ilgisi olmadığı için kesinlikle üyesi olarak değil !logic

std::ostream& operator<<(std::ostream& os, const A& a)
{
  return os << a.number;
}

3

Bu problemle şablonlu sınıflarda karşılaştım. İşte kullanmam gereken daha genel bir çözüm:

template class <T>
class myClass
{
    int myField;

    // Helper function accessing my fields
    void toString(std::ostream&) const;

    // Friend means operator<< can use private variables
    // It needs to be declared as a template, but T is taken
    template <class U>
    friend std::ostream& operator<<(std::ostream&, const myClass<U> &);
}

// Operator is a non-member and global, so it's not myClass<U>::operator<<()
// Because of how C++ implements templates the function must be
// fully declared in the header for the linker to resolve it :(
template <class U>
std::ostream& operator<<(std::ostream& os, const myClass<U> & obj)
{
  obj.toString(os);
  return os;
}

Şimdi: * cpp'de saklanacaksa, toString () işlevim satır içi olamaz. * Başlıkta bir kod kalmışsın, ondan kurtulamadım. * Operatör toString () yöntemini çağıracaktır, satır içi değildir.

<< operatörünün gövdesi, arkadaş cümlesinde veya sınıfın dışında bildirilebilir. Her iki seçenek de çirkin. :(

Belki yanlış anlıyorum veya bir şeyi kaçırıyorum, ancak sadece operatör şablonunu ileri doğru beyan etmek gcc'ye bağlanmıyor.

Bu da işe yarar:

template class <T>
class myClass
{
    int myField;

    // Helper function accessing my fields
    void toString(std::ostream&) const;

    // For some reason this requires using T, and not U as above
    friend std::ostream& operator<<(std::ostream&, const myClass<T> &)
    {
        obj.toString(os);
        return os;
    }
}

İşleci << uygulamak için şablonlu olmayan bir üst sınıf kullanıyorsanız ve sanal bir toString () yöntemi kullanıyorsanız, başlıklarda bildirimleri zorlayan şablon oluşturma sorunlarından da kaçınabileceğinizi düşünüyorum.


0

operator<<Bir üye işlev olarak tanımlarsanız , üye olmayan bir işlev kullanmanızdan farklı bir ayrıştırılmış sözdizimi olacaktır operator<<. Üye olmayan operator<<, bir üyenin operator<<tekli operatör olduğu bir ikili operatördür.

// Declarations
struct MyObj;
std::ostream& operator<<(std::ostream& os, const MyObj& myObj);

struct MyObj
{
    // This is a member unary-operator, hence one argument
    MyObj& operator<<(std::ostream& os) { os << *this; return *this; }

    int value = 8;
};

// This is a non-member binary-operator, 2 arguments
std::ostream& operator<<(std::ostream& os, const MyObj& myObj)
{
    return os << myObj.value;
}

Öyleyse .... onları gerçekten nasıl çağırırsınız? Operatörler bazı yönlerden tuhaftır, bazı operator<<(...)şeyleri anlamlandırmak için söz dizimini kafanıza yazmanız için size meydan okuyacağım .

MyObj mo;

// Calling the unary operator
mo << std::cout;

// which decomposes to...
mo.operator<<(std::cout);

Veya üye olmayan ikili operatörü çağırmayı deneyebilirsiniz:

MyObj mo;

// Calling the binary operator
std::cout << mo;

// which decomposes to...
operator<<(std::cout, mo);

Bu operatörleri üye işlevlerine dönüştürdüğünüzde sezgisel davranmaya zorlama yükümlülüğünüz yoktur, isterseniz operator<<(int)bazı üye değişkenlerini sola kaydırmayı tanımlayabilirsiniz , kaç tane yorum yaparsanız yapın, insanların biraz hazırlıksız yakalanabileceğini anlayabilirsiniz. yazmak.

Neredeyse son olarak, bir operatör çağrısı için her iki ayrıştırmanın da geçerli olduğu zamanlar olabilir, burada başınız belaya girebilir ve bu konuşmayı erteleyeceğiz.

Son olarak, ikili bir operatör gibi görünmesi gereken bir tekli üye operatörü yazmanın ne kadar garip olabileceğine dikkat edin (çünkü üye operatörleri sanal hale getirebilirsiniz ..... ayrıca bu yolu devretmemeye ve çalıştırmaya çalışmayın .... )

struct MyObj
{
    // Note that we now return the ostream
    std::ostream& operator<<(std::ostream& os) { os << *this; return os; }

    int value = 8;
};

Bu sözdizimi artık birçok kodlayıcıyı rahatsız edecek ...

MyObj mo;

mo << std::cout << "Words words words";

// this decomposes to...
mo.operator<<(std::cout) << "Words words words";

// ... or even further ...
operator<<(mo.operator<<(std::cout), "Words words words");

coutBuradaki zincirdeki ikinci argümanın nasıl olduğuna dikkat edin .... garip değil mi?

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.