ошибка: запрос на член '..' в '..', который не является типом класса

441

У меня есть класс с двумя конструкторами, один из которых не имеет аргументов, а другой - один аргумент.

Создание объектов с использованием конструктора, который принимает один аргумент, работает как ожидалось. Однако, если я создаю объекты, используя конструктор, который не принимает аргументов, я получаю ошибку.

Например, если я скомпилирую этот код (используя 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;
}

... я получаю следующую ошибку:

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

Почему это так, и как мне заставить это работать?

sarnesjo
источник
связанные: stackoverflow.com/q/2318650/69537
Meysam

Ответы:

662
Foo foo2();

изменить на

Foo foo2;

Вы получаете ошибку, потому что компилятор думает о

Foo foo2()

как объявление функции с именем 'foo2' и типом возврата 'Foo'.

Но в этом случае, если мы изменим на Foo foo2, компилятор может показать ошибку " call of overloaded ‘Foo()’ is ambiguous".

Николай Голубев
источник
6
Я не понимаю, почему компилятор думает: Foo foo2 () как объявление функции внутри основной функции.
chaviaras michalis
Видимо, я получил этот ответ раньше, так как я не могу снова проголосовать за него! Вот текстовое 2-е upvote ... и 2-е спасибо!
bigjosh
1
Объявление функции без параметров должно иметь обязательный параметр «void», чтобы такое использование было разрешено с точки зрения согласованности. Если я не ошибаюсь, в K & R C обязательно использовался термин void.
Раджеш
@Rajesh: пустой список параметров не является обязательным, он просто означает что-то отличное (нулевые параметры) от пустого списка параметров (неопределенные параметры).
Бен Фойгт
1
это еще одна веская причина для перехода на унифицированный синтаксис {} инициализации, представленный в c ++ 11
Sumudu
41

Только для записи..

На самом деле это не решение вашего кода, но у меня было то же сообщение об ошибке при неправильном доступе к методу экземпляра класса, на который указывает myPointerToClass, например,

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

где

myPointerToClass->aMethodOfThatClass();

было бы, очевидно, правильно.

ezdazuzena
источник
11

Добавляя в базу знаний, я получил ту же ошибку для

if(class_iter->num == *int_iter)

Хотя IDE дал мне правильные члены для class_iter. Очевидно, проблема в том, что "anything"::iteratorне вызывается член, numпоэтому мне нужно разыменовать его. Который не работает так:

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

...по всей видимости. Я в конце концов решил это с этим:

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

Я надеюсь, что это поможет тому, кто сталкивается с этим вопросом, как я.

Matt
источник
8

Скобки не требуются для создания экземпляров объекта класса, если вы не собираетесь использовать параметризованный конструктор.

Просто используйте Foo foo2;

Это будет работать.

Рина Сирил
источник
7

У меня была похожая ошибка, похоже, что компилятор неправильно понял вызов конструктора без аргументов. Я сделал это, удалив скобки из объявления переменной, в вашем коде что-то вроде этого:

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
Это тот же ответ, что и выше
Greenonline
1
Наиболее раздражающий синтаксический анализ не так много , что компилятор не понял, как это , что стандарт требует , чтобы компилятор интерпретировать все , что может быть объявлением функции как объявление функции, чтобы предотвратить двусмысленность.
Джастин Тайм - Восстановить Монику
(В частности, между [stmt.ambig/1]и [dcl.ambig.res/1]в стандарте прямо указывается, что в случае неоднозначности все, что можно интерпретировать как объявление, является декларацией, чтобы разрешить эту неоднозначность.)
Время Джастина - Восстановить Монику
2

Я столкнулся с случаем, когда я получил это сообщение об ошибке и имел

Foo foo(Bar());

и в основном пытался передать временный объект Bar конструктору Foo. Оказывается, компилятор переводил это

Foo foo(Bar(*)());

то есть объявление функции, чье имя foo возвращает Foo, принимающий аргумент - указатель на функцию, возвращающий Bar с 0 аргументами. При прохождении временных темпов, таких как этот, лучше использовать Bar{}вместо Bar()устранения двусмысленности.

solstice333
источник
0

Если вы хотите объявить новое вещество без параметров (зная, что у объекта есть параметры по умолчанию), не пишите

 type substance1();

но

 type substance;
Мо эль
источник
0

Конечно, это ключевой случай этой ошибки, но я получил ее в другой ситуации, когда пытался перегрузить присвоение operator=. Это было немного загадочно IMO (из 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;
}

Я получил 2 "одинаковые" ошибки

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

(Эквивалентная погрешность clangсоставляет: error: member reference base type 'float' is not a structure or union)

для линий data.i = data;и data.f = data;. Оказывается, компилятор путал имя локальной переменной 'data' и мою переменную-член data. Когда я изменил это на void operator=(T newData)и data.i = newData;, data.f = newData;ошибка ушла.

Яно
источник
0

@MykolaGolubyev уже дал замечательное объяснение. Я искал решение для чего-то подобного, MyClass obj ( MyAnotherClass() )но компилятор интерпретировал его как объявление функции.

C ++ 11 имеет фигурный список инициализации . Используя это, мы можем сделать что-то вроде этого

Temp t{String()};

Тем не менее, это:

Temp t(String());

выдает ошибку компиляции, как она считает, tкак тип 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
источник