errore: richiesta per il membro '..' in '..' che è di tipo non di classe


440

Ho una classe con due costruttori, uno che non accetta argomenti e uno che accetta un argomento.

La creazione di oggetti mediante il costruttore che accetta un argomento funziona come previsto. Tuttavia, se creo oggetti utilizzando il costruttore che non accetta argomenti, viene visualizzato un errore.

Ad esempio, se compilo questo codice (usando g ++ 4.0.1) ...

class Foo
{
  public:
    Foo() {};
    Foo(int a) {};
    void bar() {};
};

int main()
{
  // this works...
  Foo foo1(1);
  foo1.bar();

  // this does not...
  Foo foo2();
  foo2.bar();

  return 0;
}

... Ottengo il seguente errore:

nonclass.cpp: In function int main(int, const char**)’:
nonclass.cpp:17: error: request for member bar in foo2’, which is of non-class type Foo ()()’

Perché è questo e come posso farlo funzionare?


Risposte:


662
Foo foo2();

cambia in

Foo foo2;

Si ottiene l'errore perché il compilatore pensa

Foo foo2()

a partire dalla dichiarazione di funzione con il nome 'foo2' e il tipo restituito 'Foo'.

Ma in tal caso, se passiamo a Foo foo2, il compilatore potrebbe mostrare l'errore " call of overloaded ‘Foo()’ is ambiguous".


6
Non capisco perché il compilatore pensi: Foo foo2 () come da dichiarazione di funzione, all'interno della funzione principale.
Chaviaras Michalis,

Apparentemente sono arrivato a questa risposta in precedenza poiché non posso votarla di nuovo! Ecco un secondo voto testuale ... e un secondo grazie!
bigjosh

1
La dichiarazione di funzione senza parametri dovrebbe aver richiesto il parametro "vuoto" in modo che questo utilizzo sia stato consentito dal punto di vista della coerenza. Se non sbaglio, K&R C ha fatto uso obbligatorio del termine nullo.
Rajesh,

@Rajesh: un elenco di parametri vuoto non è obbligatorio, significa solo qualcosa di diverso (parametri zero) da un elenco di parametri vuoto (parametri non specificati).
Ben Voigt,

1
questo è un altro buon motivo per passare alla sintassi di inizializzazione {} uniforme introdotta in c ++ 11
Sumudu,

41

Solo per la cronaca..

In realtà non è una soluzione al tuo codice, ma ho avuto lo stesso messaggio di errore quando si accede in modo errato al metodo di un'istanza di classe a cui punta myPointerToClass, ad es.

MyClass* myPointerToClass = new MyClass();
myPointerToClass.aMethodOfThatClass();

dove

myPointerToClass->aMethodOfThatClass();

sarebbe ovviamente corretto.


11

Aggiungendo alla knowledge base, ho avuto lo stesso errore per

if(class_iter->num == *int_iter)

Anche se l'IDE mi ha dato i membri corretti per class_iter. Ovviamente, il problema è che "anything"::iteratornon ha un membro chiamato, numquindi devo dereferenziarlo. Che non funziona così:

if(*class_iter->num == *int_iter)

...apparentemente. Alla fine l'ho risolto con questo:

if((*class_iter)->num == *int_iter)

Spero che questo aiuti qualcuno che incontra questa domanda come ho fatto io.


8

La parentesi non è richiesta per creare un'istanza di un oggetto di classe quando non si intende utilizzare un costruttore con parametri.

Usa Foo foo2;

Funzionerà.


7

Stavo riscontrando un errore simile, sembra che il compilatore abbia frainteso la chiamata al costruttore senza argomenti. L'ho fatto funzionare rimuovendo la parentesi dalla dichiarazione delle variabili, nel tuo codice qualcosa del genere:

class Foo
{
  public:
    Foo() {};
    Foo(int a) {};
    void bar() {};
};

int main()
{
  // this works...
  Foo foo1(1);
  foo1.bar();

  // this does not...
  Foo foo2; // Without "()" 
  foo2.bar();

  return 0;
}

1
Questa è la stessa risposta di quella sopra
Greenonline

1
L' analisi più fastidiosa non è così tanto che il compilatore ha frainteso, in quanto lo standard richiede al compilatore di interpretare qualsiasi cosa che possa essere una dichiarazione di funzione come una dichiarazione di funzione, per evitare ambiguità.
Justin Time - Ripristina Monica

(In particolare, tra [stmt.ambig/1]e [dcl.ambig.res/1], lo standard afferma esplicitamente che in caso di ambiguità, tutto ciò che può essere interpretato come una dichiarazione È una dichiarazione, per risolvere tale ambiguità.)
Justin Time - Ripristina Monica

2

Mi sono imbattuto in un caso in cui ho ricevuto quel messaggio di errore e ho avuto

Foo foo(Bar());

e sostanzialmente cercava di passare un oggetto Bar temporaneo al costruttore Foo. Si scopre che il compilatore lo stava traducendo in

Foo foo(Bar(*)());

vale a dire, una dichiarazione di funzione il cui nome è foo che restituisce un Foo che accetta un argomento - un puntatore a funzione che restituisce una barra con 0 argomenti. Quando si passa in provvisori come questo, è meglio usare Bar{}invece di Bar()eliminare l'ambiguità.


0

Se si desidera dichiarare una nuova sostanza senza parametri (sapendo che l'oggetto ha parametri predefiniti) non scrivere

 type substance1();

ma

 type substance;

0

Certamente un caso d'angolo per questo errore, ma l'ho ricevuto in una situazione diversa, quando ho tentato di sovraccaricare il compito operator=. Era un po 'criptico IMO (da g ++ 8.1.1).

#include <cstdint>

enum DataType
{
  DT_INT32,
  DT_FLOAT
};

struct PrimitiveData
{
  union MyData
  {
    int32_t i;
    float f;
  } data;

  enum DataType dt;

  template<typename T>
  void operator=(T data)
  {
    switch(dt)
    {
      case DT_INT32:
      {
        data.i = data;
        break;
      }
      case DT_FLOAT:
      {
        data.f = data;
        break;
      }
      default:
      {
        break;
      }
    }
  }
};

int main()
{
  struct PrimitiveData pd;
  pd.dt = DT_FLOAT;
  pd = 3.4f;

  return 0;
}

Ho ricevuto 2 errori "identici"

error: request for member i [and 'f'] in data’, which is of non-class type float

(L'errore equivalente per clangè error: member reference base type 'float' is not a structure or union:)

per le linee data.i = data;e data.f = data;. Si scopre che il compilatore stava confondendo il nome della variabile locale "data" e la mia variabile membro data. Quando ho cambiato questo void operator=(T newData)e data.i = newData;, data.f = newData;, l'errore è andato via.


0

@MykolaGolubyev ha già dato una spiegazione meravigliosa. Stavo cercando una soluzione per fare qualcosa del genereMyClass obj ( MyAnotherClass() ) ma il compilatore la stava interpretando come una dichiarazione di funzione.

C ++ 11 ha una lista di controventi init . Usando questo possiamo fare qualcosa del genere

Temp t{String()};

Tuttavia, questo:

Temp t(String());

genera un errore di compilazione considerato tcome di tipo Temp(String (*)()).

#include <iostream>

class String {
public:
    String(const char* str): ptr(str)
    {
        std::cout << "Constructor: " << str << std::endl;
    }
    String(void): ptr(nullptr)
    {
        std::cout << "Constructor" << std::endl;
    }
    virtual ~String(void)
    {
        std::cout << "Destructor" << std::endl;
    }

private:
    const char *ptr;
};

class Temp {
public:
    Temp(String in): str(in)
    {
        std::cout << "Temp Constructor" << std::endl;
    }

    Temp(): str(String("hello"))
    {
        std::cout << "Temp Constructor: 2" << std::endl;
    }
    virtual ~Temp(void)
    {
        std::cout << "Temp Destructor" << std::endl;
    }

    virtual String get_str()
    {
        return str;
    }

private:
    String str;
};

int main(void)
{
    Temp t{String()}; // Compiles Success!
    // Temp t(String()); // Doesn't compile. Considers "t" as of type: Temp(String (*)())
    t.get_str(); // dummy statement just to check if we are able to access the member
    return 0;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.