오류 : 클래스가 아닌 유형 인 '..'의 멤버 '..'에 대한 요청


440

두 개의 생성자가있는 클래스가 있는데 하나는 인수를 사용하지 않고 다른 하나는 인수를 사용합니다.

하나의 인수를 취하는 생성자를 사용하여 객체를 생성하면 예상대로 작동합니다. 그러나 인수를 사용하지 않는 생성자를 사용하여 객체를 만들면 오류가 발생합니다.

예를 들어,이 코드를 컴파일하면 (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 ()()’

이것이 왜 왜 작동합니까?


답변:


661
Foo foo2();

로 변경

Foo foo2;

컴파일러가 생각하기 때문에 오류가 발생합니다.

Foo foo2()

이름이 'foo2'이고 반환 유형이 'Foo'인 함수 선언

그러나이 경우로 변경 Foo foo2하면 컴파일러에서 오류가 표시 될 수 있습니다 " call of overloaded ‘Foo()’ is ambiguous".


6
컴파일러가 왜 주 함수 내부에서 함수 선언으로 Foo foo2 ()를 생각하는지 이해하지 못합니다.
chaviaras michalis

분명히 나는 ​​다시 대답 할 수 없기 때문에이 답변에 착륙했습니다! 다음은 텍스트 2 차 공짜입니다. 2 차 감사합니다!
bigjosh

1
매개 변수가없는 함수 선언은 "void"매개 변수를 위임하여 일관성있는 관점에서이 사용법이 허용되도록해야합니다. 내가 실수하지 않으면 K & R C는 강제로 void라는 용어를 사용했습니다.
Rajesh

@Rajesh : void 매개 변수리스트는 필수가 아니며, 빈 매개 변수리스트 (지정되지 않은 매개 변수)와 다른 것 (0 개의 매개 변수)을 의미합니다.
벤 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)

나는 이것이이 질문을 뛰어 넘는 사람이 내가했던 방식으로 도움이되기를 바랍니다.


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
가장 성가신 구문 분석은 이 표준이 있다는 것입니다으로, 너무 많은 것을 컴파일러 오해하지 않습니다 필요 모호성을 방지하기 위해 함수 선언과 같은 함수 선언 될 수 아무것도, 해석하는 컴파일러.
저스틴 타임-복원 Monica Monica

(특히, 표준 [stmt.ambig/1][dcl.ambig.res/1]표준 사이 에 , 모호한 경우 선언으로 해석 될 수있는 모든 것이 그 모호성을 해결하기위한 선언이라고 명시되어 있습니다.)
Justin Time-Reinstate 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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.