error: solicitud del miembro '..' en '..' que no es de tipo de clase

440

Tengo una clase con dos constructores, uno que no toma argumentos y otro que toma un argumento.

Crear objetos usando el constructor que toma un argumento funciona como se esperaba. Sin embargo, si creo objetos usando el constructor que no toma argumentos, me sale un error.

Por ejemplo, si compilo este código (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;
}

... Obtuve el siguiente error:

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

¿Por qué es esto y cómo lo hago funcionar?

sarnesjo
fuente
relacionado: stackoverflow.com/q/2318650/69537
Meysam

Respuestas:

661
Foo foo2();

cambiar a

Foo foo2;

Obtiene el error porque el compilador piensa en

Foo foo2()

a partir de la declaración de función con el nombre 'foo2' y el tipo de retorno 'Foo'.

Pero en ese caso, si cambiamos a Foo foo2, el compilador podría mostrar el error " call of overloaded ‘Foo()’ is ambiguous".

Mykola Golubyev
fuente
66
No entiendo por qué el compilador piensa: Foo foo2 () a partir de la declaración de función, dentro de la función principal.
chaviaras michalis
Aparentemente he llegado a esta respuesta antes, ¡ya que no puedo votarla de nuevo! Aquí hay un segundo mensaje de texto ... ¡y un segundo agradecimiento!
bigjosh el
1
La declaración de función sin parámetros debería haber ordenado el parámetro "nulo" para que este uso se hubiera permitido desde el punto de vista de la coherencia. Si no me equivoco, K&R C tenía un uso obligatorio del término nulo.
Rajesh
@Rajesh: Una lista de parámetros vacía no es obligatoria, solo significa algo diferente (parámetros cero) de una lista de parámetros vacía (parámetros no especificados).
Ben Voigt
1
esta es otra buena razón para cambiar a la sintaxis de inicialización uniforme {} introducida en c ++ 11
Sumudu
41

Para que conste..

En realidad, no es una solución a su código, pero recibí el mismo mensaje de error cuando accedí incorrectamente al método de una instancia de clase señalado por myPointerToClass, por ejemplo,

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

dónde

myPointerToClass->aMethodOfThatClass();

obviamente sería correcto

ezdazuzena
fuente
11

Agregando a la base de conocimiento, obtuve el mismo error para

if(class_iter->num == *int_iter)

Aunque el IDE me dio los miembros correctos para class_iter. Obviamente, el problema es que "anything"::iteratorno tiene un miembro llamado, numasí que necesito desreferenciarlo. Lo que no funciona así:

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

...aparentemente. Finalmente lo resolví con esto:

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

Espero que esto ayude a alguien que se encuentre con esta pregunta como lo hice yo.

Mate
fuente
8

No se requiere paréntesis para crear una instancia de un objeto de clase cuando no tiene la intención de utilizar un constructor parametrizado.

Solo usa Foo foo2;

Funcionará.

Reena Cyril
fuente
7

Estaba teniendo un error similar, parece que el compilador no entiende la llamada al constructor sin argumentos. Lo hice funcionar eliminando el paréntesis de la declaración de variable, en su código algo como esto:

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;
}
Alexis Lopez Zubieta
fuente
1
Esta es la misma respuesta que la anterior
Greenonline
1
El análisis más desconcertante no es tanto que el compilador haya entendido mal, sino que el estándar requiere que el compilador interprete cualquier cosa que pueda ser una declaración de función como una declaración de función, para evitar la ambigüedad.
Justin Time - Restablece a Monica
(Específicamente, entre [stmt.ambig/1]y [dcl.ambig.res/1], el estándar establece explícitamente que, en caso de ambigüedad, cualquier cosa que pueda interpretarse como una declaración ES una declaración, para resolver esa ambigüedad.)
Justin Time - Reincorporar a Monica
2

Me encontré con un caso en el que recibí ese mensaje de error y tuve

Foo foo(Bar());

y básicamente estaba tratando de pasar un objeto Bar temporal al constructor Foo. Resulta que el compilador estaba traduciendo esto a

Foo foo(Bar(*)());

es decir, una declaración de función cuyo nombre es foo que devuelve un Foo que toma un argumento, un puntero de función que devuelve una barra con 0 argumentos. Al pasar por temporarios como este, es mejor usarlos en Bar{}lugar de Bar()eliminar la ambigüedad.

solsticio333
fuente
0

Si desea declarar una nueva sustancia sin parámetro (sabiendo que el objeto tiene parámetros predeterminados) no escriba

 type substance1();

pero

 type substance;
Mo el
fuente
0

Ciertamente, un caso de esquina para este error, pero lo recibí en una situación diferente, al intentar sobrecargar la asignación operator=. Fue un poco críptico IMO (de 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;
}

Recibí 2 errores "idénticos"

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

(El error equivalente para clanges: error: member reference base type 'float' is not a structure or union )

para las líneas data.i = data;y data.f = data;. Resulta que el compilador estaba confundiendo el nombre de la variable local 'data' y mi variable miembro data. Cuando cambié a este void operator=(T newData)y data.i = newData;, data.f = newData;el error fue.

yano
fuente
0

@MykolaGolubyev ya ha dado una explicación maravillosa. Estaba buscando una solución para hacer algo como estoMyClass obj ( MyAnotherClass() ) pero el compilador lo interpretaba como una declaración de función.

C ++ 11 tiene braced-init-list . Usando esto podemos hacer algo como esto

Temp t{String()};

Sin embargo, esto:

Temp t(String());

arroja un error de compilación ya que lo considera tde 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;
}
abhiarora
fuente