error: pedido para o membro '..' em '..' que não é do tipo de classe

439

Eu tenho uma classe com dois construtores, um que não aceita argumentos e outro que aceita um argumento.

Criar objetos usando o construtor que usa um argumento funciona como esperado. No entanto, se eu criar objetos usando o construtor que não aceita argumentos, recebo um erro.

Por exemplo, se eu compilar esse 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;
}

... Estou tendo o erro a seguir:

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 que isso e como faço para funcionar?

sarnesjo
fonte

Respostas:

660
Foo foo2();

mudar para

Foo foo2;

Você recebe o erro porque o compilador pensa em

Foo foo2()

a partir da declaração da função com o nome 'foo2' e o tipo de retorno 'Foo'.

Mas nesse caso, se mudarmos para Foo foo2, o compilador pode mostrar o erro " call of overloaded ‘Foo()’ is ambiguous".

Mykola Golubyev
fonte
6
Não entendo por que o compilador pensa: Foo foo2 () como declaração de função, dentro da função principal.
Chaviaras michalis
Aparentemente, eu já cheguei a essa resposta antes, pois não posso votá-la novamente! Aqui está um segundo voto textual ... e um segundo obrigado!
precisa saber é o seguinte
1
A declaração de função sem parâmetros deve ter o parâmetro "void" obrigatório, para que esse uso seja permitido do ponto de vista da consistência. Se não me engano, a K&R C tinha o uso obrigatório do termo nulo.
Rajesh
@Rajesh: Uma lista de parâmetros nula não é obrigatória, apenas significa algo diferente (zero parâmetros) de uma lista de parâmetros vazia (parâmetros não especificados).
Ben Voigt
1
esse é outro bom motivo para mudar para a uniforme {} sintaxe de inicialização introduzida no c ++ 11
Sumudu 28/18
41

Apenas para o registro ..

Na verdade, não é uma solução para o seu código, mas recebi a mesma mensagem de erro ao acessar incorretamente o método de uma instância de classe apontada por myPointerToClass, por exemplo

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

Onde

myPointerToClass->aMethodOfThatClass();

obviamente estaria correto.

ezdazuzena
fonte
11

Adicionando à base de conhecimento, recebi o mesmo erro para

if(class_iter->num == *int_iter)

Mesmo que o IDE tenha me dado os membros corretos para class_iter. Obviamente, o problema é que "anything"::iteratornão há um membro chamado, numentão eu preciso desreferê-lo. O que não funciona assim:

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

...pelo visto. Eu finalmente resolvi isso com isso:

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

Espero que isso ajude alguém que se depara com essa questão da maneira que eu fiz.

Matt
fonte
8

Parênteses não são necessários para instanciar um objeto de classe quando você não pretende usar um construtor parametrizado.

Basta usar Foo foo2;

Vai funcionar.

Reena Cyril
fonte
7

Eu estava tendo um erro semelhante, parece que o compilador não entende a chamada para o construtor sem argumentos. Eu fiz funcionar removendo os parênteses da declaração da variável, no seu código, algo como isto:

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
fonte
1
Esta é a mesma resposta que a acima
Greenonline 17/03/2015
1
A análise mais irritante não é tanto que o compilador tenha entendido mal, pois o padrão exige que o compilador interprete qualquer coisa que possa ser uma declaração de função como uma declaração de função, para evitar ambiguidade.
Justin Time - Restabelecer Monica
(Especificamente, entre [stmt.ambig/1]e [dcl.ambig.res/1], o padrão declara explicitamente que, em caso de ambiguidade, qualquer coisa que possa ser interpretada como uma declaração É uma declaração, para resolver essa ambiguidade.)
Justin Time - Reinstate Monica
2

Encontrei um caso em que recebi a mensagem de erro e tive

Foo foo(Bar());

e estava basicamente tentando passar um objeto Bar temporário para o construtor Foo. Acontece que o compilador estava traduzindo isso para

Foo foo(Bar(*)());

isto é, uma declaração de função cujo nome é foo que retorna um Foo que recebe um argumento - um ponteiro de função retornando uma barra com 0 argumentos. Ao passar em temporários como este, é melhor usar em Bar{}vez de Bar()eliminar a ambiguidade.

solstice333
fonte
0

Se você deseja declarar uma nova substância sem parâmetro (sabendo que o objeto tem parâmetros padrão), não escreva

 type substance1();

mas

 type substance;
Mo el
fonte
0

Certamente, este é um dos principais argumentos para esse erro, mas eu o recebi em uma situação diferente ao tentar sobrecarregar a tarefa operator=. Era um IMO um pouco enigmático (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;
}

Eu recebi 2 erros "idênticos"

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

(O erro equivalente para clangé error: member reference base type 'float' is not a structure or union:)

para as linhas data.i = data;e data.f = data;. Acontece que o compilador estava confundindo o nome da variável local 'data' e minha variável de membro data. Quando eu mudei isso void operator=(T newData)e data.i = newData;, data.f = newData;, o erro foi embora.

você não
fonte
0

@MykolaGolubyev já deu uma explicação maravilhosa. Eu estava procurando uma solução para fazer algo assimMyClass obj ( MyAnotherClass() ) mas o compilador a interpretou como uma declaração de função.

O C ++ 11 possui uma lista-init-braced . Usando isso, podemos fazer algo parecido com isto

Temp t{String()};

No entanto, isto:

Temp t(String());

lança erro de compilação, pois considera tcomo do 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
fonte