Fehler: Anforderung für Mitglied '..' in '..', das nicht vom Klassentyp ist


439

Ich habe eine Klasse mit zwei Konstruktoren, einer ohne Argumente und einer mit einem Argument.

Das Erstellen von Objekten mit dem Konstruktor, der ein Argument verwendet, funktioniert wie erwartet. Wenn ich jedoch Objekte mit dem Konstruktor erstelle, der keine Argumente akzeptiert, wird eine Fehlermeldung angezeigt.

Zum Beispiel, wenn ich diesen Code kompiliere (mit 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;
}

... ich bekomme folgenden Fehler:

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 ()()’

Warum ist das so und wie bringe ich es zum Laufen?


Antworten:


660
Foo foo2();

ändern

Foo foo2;

Sie erhalten den Fehler, weil der Compiler daran denkt

Foo foo2()

ab Funktionsdeklaration mit dem Namen 'foo2' und dem Rückgabetyp 'Foo'.

In diesem Fall Foo foo2zeigt der Compiler möglicherweise den Fehler an , wenn wir zu wechseln " call of overloaded ‘Foo()’ is ambiguous".


6
Ich verstehe nicht, warum der Compiler denkt: Foo foo2 () ab Funktionsdeklaration innerhalb der Hauptfunktion.
Chaviaras Michalis

Anscheinend bin ich schon einmal auf diese Antwort gestoßen, da ich sie nicht noch einmal bewerten kann! Hier ist eine textuelle 2. Gegenstimme ... und ein 2. Dankeschön!
Bigjosh

1
Die parameterlose Funktionsdeklaration sollte den Parameter "void" vorschreiben, damit diese Verwendung unter Konsistenzgesichtspunkten zulässig wäre. Wenn ich mich nicht irre, hatte K & R C die obligatorische Verwendung des Begriffs nichtig.
Rajesh

@ Rajesh: Eine leere Parameterliste ist nicht obligatorisch, sondern bedeutet nur etwas anderes (Nullparameter) als eine leere Parameterliste (nicht spezifizierte Parameter).
Ben Voigt

1
Dies ist ein weiterer guter Grund, auf die einheitliche {} Initialisierungssyntax
umzusteigen,

41

Nur für das Protokoll..

Es ist eigentlich keine Lösung für Ihren Code, aber ich hatte die gleiche Fehlermeldung, wenn ich falsch auf die Methode einer Klasseninstanz zugegriffen habe myPointerToClass, auf die z

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

wo

myPointerToClass->aMethodOfThatClass();

wäre natürlich richtig.


11

Beim Hinzufügen zur Wissensdatenbank habe ich den gleichen Fehler für erhalten

if(class_iter->num == *int_iter)

Obwohl die IDE mir die richtigen Mitglieder für class_iter gegeben hat. Offensichtlich ist das Problem, dass "anything"::iteratorkein Mitglied angerufen wird, numalso muss ich es dereferenzieren. Was so nicht funktioniert:

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

...anscheinend. Ich habe es schließlich damit gelöst:

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

Ich hoffe, das hilft jemandem, der diese Frage so wie ich beantwortet.


8

Eine Klammer ist nicht erforderlich, um ein Klassenobjekt zu instanziieren, wenn Sie keinen parametrisierten Konstruktor verwenden möchten.

Verwenden Sie einfach Foo foo2;

Es wird klappen.


7

Ich hatte einen ähnlichen Fehler, es scheint, dass der Compiler den Aufruf des Konstruktors ohne Argumente falsch versteht. Ich habe es geschafft, indem ich die Klammer aus der Variablendeklaration in Ihrem Code entfernt habe:

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
Dies ist die gleiche Antwort wie oben
Greenonline

1
Die ärgerlichste Analyse ist nicht so sehr, dass der Compiler sie missverstanden hat, da der Compiler vom Standard verlangt , alles, was eine Funktionsdeklaration sein könnte, als Funktionsdeklaration zu interpretieren, um Mehrdeutigkeiten zu vermeiden.
Justin Time - Setzen Sie Monica

(Insbesondere zwischen [stmt.ambig/1]und [dcl.ambig.res/1]besagt der Standard ausdrücklich, dass im Falle von Mehrdeutigkeiten alles, was als Erklärung interpretiert werden kann, eine Erklärung ist, um diese Mehrdeutigkeit zu beheben.)
Justin Time - Wiedereinsetzung von Monica

2

Ich bin auf einen Fall gestoßen, in dem ich diese Fehlermeldung erhalten habe und hatte

Foo foo(Bar());

und versuchte im Grunde, ein temporäres Bar-Objekt an den Foo-Konstruktor zu übergeben. Es stellte sich heraus, dass der Compiler dies übersetzt hat

Foo foo(Bar(*)());

Das heißt, eine Funktionsdeklaration mit dem Namen foo, die ein Foo zurückgibt, das ein Argument aufnimmt - einen Funktionszeiger, der einen Balken mit 0 Argumenten zurückgibt. Wenn in Provisorien wie dies vorbei, besser zu nutzen , Bar{}anstatt Bar()Mehrdeutigkeit zu beseitigen.


0

Wenn Sie eine neue Substanz ohne Parameter deklarieren möchten (in dem Wissen, dass das Objekt Standardparameter hat), schreiben Sie nicht

 type substance1();

aber

 type substance;

0

Sicherlich ein Eckfall für diesen Fehler, aber ich habe ihn in einer anderen Situation erhalten, als ich versucht habe, die Zuordnung zu überladen operator=. Es war ein bisschen kryptisch IMO (ab 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;
}

Ich habe 2 "identische" Fehler erhalten

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

(Der entsprechende Fehler für clangist: error: member reference base type 'float' is not a structure or union )

für die Zeilen data.i = data;und data.f = data;. Es stellte sich heraus, dass der Compiler den lokalen Variablennamen 'data' und meine Mitgliedsvariable verwechselt hat data. Als ich dies in void operator=(T newData)und data.i = newData;, änderte data.f = newData;, verschwand der Fehler.


0

@ MykolaGolubyev hat bereits wunderbare Erklärungen gegeben. Ich suchte nach einer Lösung, um so etwas zu tunMyClass obj ( MyAnotherClass() ) aber der Compiler interpretierte es als Funktionsdeklaration.

C ++ 11 hat eine Klammer-Init-Liste . Damit können wir so etwas machen

Temp t{String()};

Dies ist jedoch:

Temp t(String());

löst einen Kompilierungsfehler aus, der tvom Typ abhängt 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;
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.