lỗi: yêu cầu thành viên '..' trong '..' thuộc loại không thuộc lớp


439

Tôi có một lớp với hai hàm tạo, một lớp không có đối số và một lớp lấy một đối số.

Tạo các đối tượng bằng cách sử dụng hàm tạo có một đối số hoạt động như mong đợi. Tuy nhiên, nếu tôi tạo các đối tượng bằng cách sử dụng hàm tạo không có đối số, tôi sẽ gặp lỗi.

Chẳng hạn, nếu tôi biên dịch mã này (sử dụng 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;
}

... Tôi nhận được lỗi sau đây:

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

Tại sao điều này, và làm thế nào để tôi làm cho nó hoạt động?


Câu trả lời:


660
Foo foo2();

thay đổi thành

Foo foo2;

Bạn gặp lỗi vì trình biên dịch nghĩ về

Foo foo2()

như khai báo hàm với tên 'foo2' và kiểu trả về 'Foo'.

Nhưng trong trường hợp đó Nếu chúng ta thay đổi thành Foo foo2, trình biên dịch có thể hiển thị lỗi " call of overloaded ‘Foo()’ is ambiguous".


6
Tôi không hiểu tại sao trình biên dịch nghĩ: Foo foo2 () là khai báo hàm, bên trong hàm chính.
chaviara michalis

Rõ ràng tôi đã đáp ứng câu trả lời này trước đây vì tôi không thể đưa ra câu trả lời một lần nữa! Đây là một upvote thứ 2 văn bản ... và một lời cảm ơn thứ 2!
bigjosh

1
Khai báo hàm không tham số nên có tham số "void" bắt buộc để việc sử dụng này được cho phép theo quan điểm nhất quán. Nếu tôi không nhầm, K & R C đã sử dụng bắt buộc sử dụng khoảng trống.
Rajesh

@Rajesh: Danh sách tham số void không bắt buộc, nó chỉ có nghĩa là một cái gì đó khác (tham số không) từ danh sách tham số trống (tham số không xác định).
Ben Voigt

1
đây là một lý do chính đáng khác để chuyển sang cú pháp khởi tạo {} thống nhất giới thiệu trong c ++ 11
Sumudu

41

Chỉ để cho bản ghi âm thôi..

Nó thực sự không phải là một giải pháp cho mã của bạn, nhưng tôi đã có cùng một thông báo lỗi khi truy cập không chính xác phương thức của một thể hiện lớp được chỉ ra bởi myPointerToClass, vd

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

Ở đâu

myPointerToClass->aMethodOfThatClass();

Rõ ràng là sẽ đúng.


11

Thêm vào cơ sở kiến ​​thức, tôi đã nhận được lỗi tương tự cho

if(class_iter->num == *int_iter)

Mặc dù IDE đã cho tôi các thành viên chính xác cho class_iter. Rõ ràng, vấn đề là "anything"::iteratorkhông có thành viên nào được gọi numnên tôi cần phải hủy đăng ký. Mà không hoạt động như thế này:

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

... Rõ ràng. Cuối cùng tôi đã giải quyết nó bằng cách này:

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

Tôi hy vọng điều này sẽ giúp ai đó chạy qua câu hỏi này theo cách tôi đã làm.


8

Không cần phải có dấu ngoặc đơn để khởi tạo một đối tượng lớp khi bạn không có ý định sử dụng hàm tạo tham số.

Chỉ cần sử dụng Foo foo2;

Nó sẽ làm việc.


7

Tôi đã có một lỗi tương tự, có vẻ như trình biên dịch hiểu nhầm cuộc gọi đến hàm tạo mà không có đối số. Tôi đã làm cho nó hoạt động bằng cách loại bỏ dấu ngoặc đơn khỏi khai báo biến, trong mã của bạn một cái gì đó như thế này:

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
Đây là câu trả lời giống như câu trả lời ở trên
Greenonline 17/03/2015

1
Phân tích cú pháp khó hiểu nhất không phải là trình biên dịch hiểu sai, vì tiêu chuẩn yêu cầu trình biên dịch diễn giải bất cứ điều gì có thể là khai báo hàm như khai báo hàm, để tránh sự mơ hồ.
Thời gian của Justin - Phục hồi Monica

(Cụ thể, giữa [stmt.ambig/1][dcl.ambig.res/1], tiêu chuẩn tuyên bố rõ ràng rằng trong trường hợp không rõ ràng, bất kỳ điều gì có thể được hiểu là tuyên bố đều là tuyên bố, để giải quyết sự mơ hồ đó.)
Justin Time - Tái lập lại

2

Tôi gặp phải trường hợp tôi nhận được thông báo lỗi đó và đã

Foo foo(Bar());

và về cơ bản là cố gắng truyền một đối tượng Bar tạm thời cho hàm tạo Foo. Hóa ra trình biên dịch đã dịch cái này sang

Foo foo(Bar(*)());

nghĩa là, một khai báo hàm có tên là foo trả về một Foo nhận trong một đối số - một con trỏ hàm trả về một Bar có 0 đối số. Khi đi trong thời gian như thế này, tốt hơn để sử dụng Bar{}thay vì Bar()để loại bỏ sự mơ hồ.


0

Nếu bạn muốn khai báo một chất mới không có tham số (biết rằng đối tượng có tham số mặc định), đừng viết

 type substance1();

nhưng

 type substance;

0

Chắc chắn là một trường hợp góc cho lỗi này, nhưng tôi đã nhận được nó trong một tình huống khác, khi cố gắng làm quá tải bài tập operator=. Đó là một IMO khó hiểu (từ 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;
}

Tôi đã nhận được 2 lỗi "giống hệt nhau"

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

(Lỗi tương đương cho clangerror: member reference base type 'float' is not a structure or union:)

cho các dòng data.i = data;data.f = data;. Hóa ra trình biên dịch đã gây nhầm lẫn tên biến dữ liệu cục bộ 'dữ liệu' và biến thành viên của tôi data. Khi tôi thay đổi điều này thành void operator=(T newData)data.i = newData;, data.f = newData;lỗi đã biến mất.


0

@MykolaGolubyev đã đưa ra lời giải thích tuyệt vời. Tôi đang tìm kiếm một giải pháp để làm một cái gì đó như thế nàyMyClass obj ( MyAnotherClass() ) nhưng trình biên dịch đã diễn giải nó như là một khai báo hàm.

C ++ 11 có braces-init-list . Sử dụng cái này chúng ta có thể làm một cái gì đó như thế này

Temp t{String()};

Tuy nhiên, điều này:

Temp t(String());

ném lỗi biên dịch vì nó coi tlà loại 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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.