ข้อผิดพลาด: คำขอสำหรับสมาชิก '.. ' ใน '.. ' ซึ่งเป็นประเภทที่ไม่ใช่ชั้นเรียน


440

ฉันมีคลาสที่มีคอนสตรัคเตอร์สองตัวอันที่ไม่มีข้อโต้แย้งและอีกหนึ่งที่ใช้อาร์กิวเมนต์เดียว

การสร้างออบเจ็กต์โดยใช้ Constructor ที่รับหนึ่งอาร์กิวเมนต์ทำงานได้ตามที่คาด อย่างไรก็ตามถ้าฉันสร้างวัตถุโดยใช้ Constructor ที่ไม่มีข้อโต้แย้งฉันได้รับข้อผิดพลาด

ตัวอย่างเช่นถ้าฉันรวบรวมรหัสนี้ (ใช้ 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 ()()’

ทำไมสิ่งนี้และฉันจะทำให้มันทำงานอย่างไร


เกี่ยวข้อง: stackoverflow.com/q/2318650/69537
Meysam

คำตอบ:


661
Foo foo2();

เปลี่ยนไป

Foo foo2;

คุณได้รับข้อผิดพลาดเนื่องจากคอมไพเลอร์คิดถึง

Foo foo2()

เมื่อประกาศฟังก์ชันด้วยชื่อ 'foo2' และประเภทส่งคืน 'Foo'

แต่ในกรณีที่ว่าถ้าเราเปลี่ยนไปคอมไพเลอร์อาจแสดงข้อผิดพลาดFoo foo2 " call of overloaded ‘Foo()’ is ambiguous"


6
ฉันไม่เข้าใจว่าทำไมคอมไพเลอร์คิดว่า: Foo foo2 () ตามการประกาศฟังก์ชั่นภายในฟังก์ชั่นหลัก
chaviaras michalis

เห็นได้ชัดว่าฉันเคยตอบคำถามนี้มาก่อนเพราะฉันไม่สามารถโหวตได้อีกครั้ง! นี่คือการโหวตครั้งที่ 2 ที่เป็นข้อความ ... และขอขอบคุณที่สอง!
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)

ฉันหวังว่านี่จะช่วยให้คนที่เจอคำถามนี้ในแบบที่ฉันเป็น


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
การแยกวิเคราะห์ที่รบกวนมากที่สุดนั้นไม่มากนักที่ผู้แปลเข้าใจผิดเนื่องจากมาตรฐานกำหนดให้คอมไพเลอร์ตีความสิ่งใด ๆ ที่อาจเป็นการประกาศฟังก์ชั่นเป็นการประกาศฟังก์ชั่นเพื่อป้องกันความคลุมเครือ
Justin Time - Reinstate Monica

(โดยเฉพาะระหว่าง[stmt.ambig/1]และ[dcl.ambig.res/1]มาตรฐานระบุอย่างชัดเจนว่าในกรณีที่มีความกำกวมสิ่งใดที่สามารถตีความได้ว่าเป็นการประกาศเป็นการประกาศเพื่อแก้ไขความกำกวมนั้น)
Justin Time - Reinstate Monica

2

ฉันพบกรณีที่ฉันได้รับข้อความแสดงข้อผิดพลาดและมี

Foo foo(Bar());

และโดยทั่วไปก็พยายามส่งผ่านวัตถุบาร์ชั่วคราวไปยังผู้สร้างฟู ปรากฎว่าคอมไพเลอร์แปลข้อความนี้เป็น

Foo foo(Bar(*)());

นั่นคือการประกาศฟังก์ชั่นที่มีชื่อเป็น foo ที่ส่งกลับ Foo ที่ใช้ในการโต้แย้ง - ตัวชี้ฟังก์ชั่นกลับบาร์ที่มี 0 ข้อโต้แย้ง เมื่อผ่านในชั่วขณะเช่นนี้ดีกว่าที่จะใช้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ชื่อตัวแปรท้องถิ่นและตัวแปรสมาชิกของฉัน เมื่อฉันเปลี่ยนสิ่งนี้เป็นvoid operator=(T newData)และdata.i = newData;, data.f = newData;ข้อผิดพลาดก็หายไป


0

@ MykolaGolubyev ได้รับคำอธิบายที่ยอดเยี่ยมแล้ว ฉันกำลังมองหาวิธีแก้ปัญหาที่จะทำบางสิ่งเช่นนี้MyClass obj ( MyAnotherClass() )แต่คอมไพเลอร์แปลมันเป็นการประกาศฟังก์ชั่น

C ++ 11 มีค้ำยัน-init รายการ ใช้สิ่งนี้เราสามารถทำสิ่งนี้

Temp t{String()};

อย่างไรก็ตามสิ่งนี้:

Temp t(String());

พ่นรวบรวมข้อผิดพลาดในขณะที่จะมีการพิจารณาเป็นประเภทtTemp(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.