Der Ausdruck muss einen Klassentyp haben

81

Ich habe seit einiger Zeit nicht mehr in c ++ codiert und bin hängen geblieben, als ich versucht habe, dieses einfache Snippet zu kompilieren:

class A
{
  public:
    void f() {}
};

int main()
{
  {
    A a;
    a.f(); // works fine
  }

  {
    A *a = new A();
    a.f(); // this doesn't
  }
}
adrianton3
quelle
2
Die Zeile mit der Aufschrift "Dies ist nicht" ist in Ordnung, sodass Ihre Frage verwirrend aussieht.
Juanchopanza

Antworten:

164

Es ist ein Zeiger, also versuchen Sie stattdessen:

a->f();

Grundsätzlich wird der Operator .(der für den Zugriff auf die Felder und Methoden eines Objekts verwendet wird) für Objekte und Referenzen verwendet.

A a;
a.f();
A& ref = a;
ref.f();

Wenn Sie einen Zeigertyp haben, müssen Sie ihn zuerst dereferenzieren, um eine Referenz zu erhalten:

A* ptr = new A();
(*ptr).f();
ptr->f();

Die a->bNotation ist normalerweise nur eine Abkürzung für (*a).b.

Ein Hinweis zu intelligenten Zeigern

Das operator->kann überladen werden, was insbesondere von Smart Pointern verwendet wird. Wenn Sie intelligente Zeiger verwenden ->, beziehen Sie sich auch auf das spitze Objekt:

auto ptr = make_unique<A>();
ptr->f();
Kos
quelle
Wenn Sie gerade mit C ++ anfangen, müssen Sie es immer noch zu einem Automatismus machen, um herauszufinden, ob Sie einen Zeiger oder eine Referenz verwenden sollen. In meinem speziellen Fall brauchte ich nur eine Referenz, aber aus irgendeinem Grund habe ich stattdessen einen Zeiger übergeben. Trotzdem danke für die klare Erklärung!
Guillaume M
13

Ermöglichen Sie eine Analyse.

#include <iostream>   // not #include "iostream"
using namespace std;  // in this case okay, but never do that in header files

class A
{
 public:
  void f() { cout<<"f()\n"; }
};

int main()
{
 /*
 // A a; //this works
 A *a = new A(); //this doesn't
 a.f(); // "f has not been declared"
 */ // below


 // system("pause");  <-- Don't do this. It is non-portable code. I guess your 
 //                       teacher told you this?
 //                       Better: In your IDE there is prolly an option somewhere
 //                               to not close the terminal/console-window.
 //                       If you compile on a CLI, it is not needed at all.
}

Als allgemeiner Rat:

0) Prefer automatic variables
  int a;
  MyClass myInstance;
  std::vector<int> myIntVector;

1) If you need data sharing on big objects down 
   the call hierarchy, prefer references:

  void foo (std::vector<int> const &input) {...}
  void bar () { 
       std::vector<int> something;
       ...
       foo (something);
  }


2) If you need data sharing up the call hierarchy, prefer smart-pointers
   that automatically manage deletion and reference counting.

3) If you need an array, use std::vector<> instead in most cases.
   std::vector<> is ought to be the one default container.

4) I've yet to find a good reason for blank pointers.

   -> Hard to get right exception safe

       class Foo {
           Foo () : a(new int[512]), b(new int[512]) {}
           ~Foo() {
               delete [] b;
               delete [] a;
           }
       };

       -> if the second new[] fails, Foo leaks memory, because the
          destructor is never called. Avoid this easily by using 
          one of the standard containers, like std::vector, or
          smart-pointers.

Als Faustregel gilt: Wenn Sie den Speicher selbst verwalten müssen, steht in der Regel bereits ein Superiour-Manager oder eine Alternative zur Verfügung, die dem RAII-Prinzip folgt.

Sebastian Mach
quelle
9

Zusammenfassung : Stattdessen a.f();sollte es seina->f();

In der Hauptsache haben Sie a als Zeiger auf das Objekt von A definiert , damit Sie mit dem ->Operator auf Funktionen zugreifen können .

Ein alternativer , aber weniger lesbarer Weg ist(*a).f()

a.f()hätte verwendet werden können, um auf f () zuzugreifen, wenn a deklariert wurde als: A a;

Ozair Kafray
quelle
6

aist ein Zeiger. Sie müssen verwenden ->, nicht.

Dunkler Falke
quelle