error: request for member '..' in '..' yang bukan tipe kelas


440

Saya memiliki kelas dengan dua konstruktor, yang tidak menggunakan argumen dan yang menggunakan satu argumen.

Membuat objek menggunakan konstruktor yang mengambil satu argumen berfungsi seperti yang diharapkan. Namun, jika saya membuat objek menggunakan konstruktor yang tidak membutuhkan argumen, saya mendapatkan kesalahan.

Misalnya, jika saya mengkompilasi kode ini (menggunakan 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;
}

... Saya mendapatkan kesalahan berikut:

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

Mengapa ini, dan bagaimana saya membuatnya bekerja?


Jawaban:


662
Foo foo2();

mengubah

Foo foo2;

Anda mendapatkan kesalahan karena dipikirkan oleh kompiler

Foo foo2()

pada deklarasi fungsi dengan nama 'foo2' dan jenis kembali 'Foo'.

Tetapi dalam kasus itu Jika kita berubah ke Foo foo2, kompiler mungkin menunjukkan kesalahan " call of overloaded ‘Foo()’ is ambiguous".


6
Saya tidak mengerti mengapa kompiler berpikir: Foo foo2 () sebagai deklarasi fungsi, di dalam fungsi utama.
chaviaras michalis

Rupanya saya sudah mendapatkan jawaban ini sebelumnya karena saya tidak bisa mengulanginya lagi! Berikut ini adalah upvote kedua yang tekstual ... dan yang kedua terima kasih!
bigjosh

1
Deklarasi fungsi tanpa parameter harus diamanatkan parameter "void" sehingga penggunaan ini akan diizinkan dari sudut pandang konsistensi. Jika saya tidak salah, K&R C wajib menggunakan istilah batal.
Rajesh

@Rajesh: Daftar parameter void tidak wajib, itu hanya berarti sesuatu yang berbeda (parameter nol) dari daftar parameter kosong (parameter tidak ditentukan).
Ben Voigt

1
ini adalah alasan bagus lainnya untuk beralih ke sintaks inisialisasi {} yang diperkenalkan di c ++ 11
Sumudu

41

Hanya sebagai catatan ..

Sebenarnya ini bukan solusi untuk kode Anda, tetapi saya memiliki pesan kesalahan yang sama ketika salah mengakses metode instance kelas yang ditunjukkan oleh myPointerToClass, misalnya

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

dimana

myPointerToClass->aMethodOfThatClass();

jelas akan benar.


11

Menambah basis pengetahuan, saya mendapat kesalahan yang sama untuk

if(class_iter->num == *int_iter)

Meskipun IDE memberi saya anggota yang benar untuk class_iter. Jelas, masalahnya adalah bahwa "anything"::iteratortidak ada anggota yang dipanggil numjadi saya perlu menundanya. Yang tidak berfungsi seperti ini:

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

...tampaknya. Saya akhirnya menyelesaikannya dengan ini:

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

Saya harap ini membantu seseorang yang menghadapi pertanyaan ini seperti yang saya lakukan.


8

Parenthesis tidak diperlukan untuk instantiate objek kelas ketika Anda tidak bermaksud menggunakan konstruktor parameterised.

Cukup gunakan Foo foo2;

Itu akan berhasil.


7

Saya mengalami kesalahan yang sama, sepertinya kompiler salah paham panggilan ke konstruktor tanpa argumen. Saya membuatnya bekerja dengan menghapus tanda kurung dari deklarasi variabel, dalam kode Anda sesuatu seperti ini:

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
Ini adalah jawaban yang sama dengan yang di atas
Greenonline

1
The paling menjengkelkan parse tidak begitu banyak bahwa disalahpahami compiler, karena itu adalah bahwa standar membutuhkan compiler untuk menafsirkan apa yang mungkin menjadi deklarasi fungsi sebagai deklarasi fungsi, untuk mencegah ambiguitas.
Justin Time - Kembalikan Monica

(Secara khusus, antara [stmt.ambig/1]dan [dcl.ambig.res/1], standar secara eksplisit menyatakan bahwa dalam hal ambiguitas, apa pun yang dapat diartikan sebagai deklarasi ADALAH deklarasi, untuk menyelesaikan ambiguitas itu.)
Justin Time - Reinstate Monica

2

Saya menemukan sebuah case dimana saya mendapatkan pesan kesalahan itu dan memilikinya

Foo foo(Bar());

dan pada dasarnya mencoba meneruskan objek Bar sementara ke konstruktor Foo. Ternyata kompiler menerjemahkan ini ke

Foo foo(Bar(*)());

yaitu, deklarasi fungsi yang namanya foo yang mengembalikan Foo yang mengambil argumen - penunjuk fungsi mengembalikan Bar dengan 0 argumen. Saat melewati temporari seperti ini, lebih baik digunakan Bar{}daripada Bar()menghilangkan ambiguitas.


0

Jika Anda ingin mendeklarasikan substansi baru tanpa parameter (mengetahui bahwa objek memiliki parameter default) jangan menulis

 type substance1();

tapi

 type substance;

0

Tentu saja sudut kasus untuk kesalahan ini, tetapi saya menerimanya dalam situasi yang berbeda, ketika mencoba untuk membebani tugas operator=. Itu agak samar IMO (dari 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;
}

Saya menerima 2 kesalahan "identik"

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

(Kesalahan yang setara untuk clangadalah error: member reference base type 'float' is not a structure or union:)

untuk garis data.i = data;dan data.f = data;. Ternyata kompiler itu membingungkan nama variabel lokal 'data' dan variabel anggota saya data. Ketika saya mengubah ini menjadi void operator=(T newData)dan data.i = newData;, data.f = newData;kesalahan hilang.


0

@MykolaGolubyev telah memberikan penjelasan yang luar biasa. Saya sedang mencari solusi untuk melakukan sesuatu seperti ini MyClass obj ( MyAnotherClass() )tetapi kompiler menafsirkannya sebagai deklarasi fungsi.

C ++ 11 telah menguatkan-init-list . Dengan ini kita bisa melakukan sesuatu seperti ini

Temp t{String()};

Namun, ini:

Temp t(String());

melempar kesalahan kompilasi karena dianggap tsebagai tipe 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;
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.