错误:请求“ ..”中的成员“ ..”属于非类类型


439

我有一个带有两个构造函数的类,一个不带参数,而一个带一个参数。

使用接受一个参数的构造函数创建对象的工作符合预期。但是,如果我使用不带参数的构造函数创建对象,则会出现错误。

例如,如果我编译此代码(使用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 ()()’

为什么会这样,如何使它起作用?


Answers:


660
Foo foo2();

改成

Foo foo2;

因为编译器认为您得到错误

Foo foo2()

从名称为“ foo2”的函数声明开始,返回类型为“ Foo”。

但是在这种情况下,如果更改为Foo foo2,编译器可能会显示错误 " call of overloaded ‘Foo()’ is ambiguous"


6
我不明白为什么编译器会这样:Foo foo2()从函数声明开始,在主函数内部。
chaviaras michalis

显然我之前已经找到了这个答案,因为我无法再次投票!这是文本上的第二次投票...和第二次感谢!
bigjosh

1
无参数函数声明应已强制使用“ void”参数,以便从一致性的角度允许这种用法。如果我没记错的话,K&R C强制使用了无效一词。
Rajesh

@Rajesh:无效的参数列表不是强制性的,仅表示与空的参数列表(未指定的参数)有所不同(零参数)。
Ben Voigt

1
这是切换到统一的{}初始化语法的另一个很好的理由,c ++ 11中引入了这种语法
Sumudu

41

只是为了记录。

它实际上不是您的代码的解决方案,但是当错误地访问所指向的类实例的方法时myPointerToClass,例如,我收到了相同的错误消息

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

哪里

myPointerToClass->aMethodOfThatClass();

显然是正确的。


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)

我希望这可以帮助像我一样遇到这个问题的人。



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
最让人头疼的解析是没有这么多的编译器误解,因为它是标准要求编译器来解释什么,可能是一个函数声明为函数声明,以避免歧义。
贾斯汀时间-恢复莫妮卡

(具体来说,在[stmt.ambig/1]和之间[dcl.ambig.res/1],该标准明确指出,在歧义的情况下,任何可解释为声明的东西都是声明,以解决歧义。)
贾斯汀·时报(Justin Time)-恢复莫妮卡(Monica)

2

我遇到了一个错误消息,

Foo foo(Bar());

并基本上试图将临时Bar对象传递给Foo构造函数。原来编译器正在将其翻译成

Foo foo(Bar(*)());

也就是说,名称为foo的函数声明返回一个带参数的Foo -函数指针返回带0个参数的Bar。当这样传递临时消息时,最好使用Bar{}而不是Bar()消除歧义。


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具有braced-init-list。使用这个我们可以做这样的事情

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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.