C ++ 11 มีคุณสมบัติ C # -style หรือไม่?


94

ใน C # มีน้ำตาลไวยากรณ์ที่ดีสำหรับฟิลด์ที่มี getter และ setter นอกจากนี้ฉันชอบคุณสมบัติที่ใช้งานอัตโนมัติซึ่งอนุญาตให้ฉันเขียนได้

public Foo foo { get; private set; }

ใน C ++ ฉันต้องเขียน

private:
    Foo foo;
public:
    Foo getFoo() { return foo; }

มีแนวคิดบางอย่างใน C ++ 11 ที่อนุญาตให้ฉันมีน้ำตาลไวยากรณ์ในเรื่องนี้หรือไม่


65
สามารถทำได้โดยใช้มาโครสองสามตัว วิ่งหนีด้วยความอับอาย
Mankarse

7
@Eloff: แค่ทำให้ทุกอย่างเป็นสาธารณะก็เป็นความคิดที่แย่เสมอ
Kaiserludi

8
ไม่มีแนวคิดแบบนี้! และคุณไม่ต้องการมันด้วย: seanmiddleditch.com/why-c-does-not-need-c-like-properties
CinCout

2
a) คำถามนี้ค่อนข้างเก่า b) ฉันกำลังขอน้ำตาลไวยากรณ์ซึ่งจะช่วยให้ฉันสามารถกำจัดวงเล็บได้ c) แม้ว่าบทความจะนำเสนอข้อโต้แย้งที่ถูกต้องกับการปรับคุณสมบัติไม่ว่า C ++ 'ต้องการหรือไม่ต้องการคุณสมบัติ' เป็นเรื่องส่วนตัวมาก C ++ เทียบเท่ากับ Touring-machine แม้ว่าจะไม่มี แต่ก็ไม่ได้หมายความว่าการมีน้ำตาลไวยากรณ์ดังกล่าวจะทำให้ C ++ มีประสิทธิผลมากขึ้น
Radim Vansa

3
ไม่อย่างแน่นอน.

คำตอบ:


90

ใน C ++ คุณสามารถเขียนคุณสมบัติของคุณเองได้ นี่คือตัวอย่างการนำคุณสมบัติไปใช้โดยใช้คลาสที่ไม่มีชื่อ บทความ Wikipedia

struct Foo
{
    class {
        int value;
        public:
            int & operator = (const int &i) { return value = i; }
            operator int () const { return value; }
    } alpha;

    class {
        float value;
        public:
            float & operator = (const float &f) { return value = f; }
            operator float () const { return value; }
    } bravo;
};

คุณสามารถเขียน getters & setters ของคุณเองได้และถ้าคุณต้องการเข้าถึงสมาชิกคลาสของผู้ถือคุณสามารถขยายโค้ดตัวอย่างนี้ได้


1
มีแนวคิดเกี่ยวกับวิธีแก้ไขรหัสนี้ให้ยังคงมีตัวแปรสมาชิกส่วนตัวที่ Foo สามารถเข้าถึงได้ภายในในขณะที่ API สาธารณะจะเปิดเผยคุณสมบัติเท่านั้น? แน่นอนว่าฉันสามารถทำให้ Foo เป็นเพื่อนของ alpha / beta ได้ แต่ตอนนั้นฉันก็ยังต้องเขียน alpha.value เพื่อเข้าถึงค่า แต่ฉันต้องการมากกว่าถ้าการเข้าถึงตัวแปรสมาชิกโดยตรงจากภายใน Foo จะรู้สึกเหมือนมากกว่า เข้าถึงสมาชิกของ Foo เองและไม่ใช่สมาชิกของคลาสคุณสมบัติที่ซ้อนกันพิเศษ
Kaiserludi

1
@ Kaiserludi ใช่: ในกรณีนี้กำหนดให้ alpha และ bravo เป็นส่วนตัว ใน Foo คุณสามารถอ่าน / เขียนโดยใช้ "คุณสมบัติ" ข้างต้น แต่ภายนอก Foo จะไม่สามารถทำได้อีกต่อไป เพื่อหลีกเลี่ยงสิ่งนั้นให้ทำการอ้างอิง const ซึ่งเป็นสาธารณะ สามารถเข้าถึงได้จากภายนอก แต่สำหรับการอ่านเท่านั้นเนื่องจากเป็นการอ้างอิงอย่างต่อเนื่อง ข้อแม้เดียวคือคุณต้องมีชื่ออื่นสำหรับการอ้างอิง const สาธารณะ ฉันใช้_alphaสำหรับตัวแปรส่วนตัวและalphaเพื่อการอ้างอิงเป็นการส่วนตัว
Kapichu

1
@Kapichu: ไม่ใช่วิธีแก้ปัญหาด้วยเหตุผล 2 ประการ 1) ในคุณสมบัติ C # getters / setters มักใช้เพื่อฝังการตรวจสอบความปลอดภัยที่บังคับให้ผู้ใช้สาธารณะของคลาสในขณะที่อนุญาตให้ฟังก์ชันสมาชิกเข้าถึงค่าได้โดยตรง 2) การอ้างอิง const ไม่ได้ฟรี: ขึ้นอยู่กับคอมไพเลอร์ / sizeof(Foo)แพลตฟอร์มที่พวกเขาจะดูภาพขยาย
ceztko

@psx: เนื่องจากข้อ จำกัด ของแนวทางนี้ฉันจะหลีกเลี่ยงและรอให้มีการเพิ่มมาตรฐานที่เหมาะสมหากมันจะปรากฏขึ้น
ceztko

@Kapichu: แต่อัลฟ่าและบราโว่ในโค้ดตัวอย่างเป็นคุณสมบัติ ฉันต้องการเข้าถึงตัวแปรโดยตรงจากภายในการใช้งาน Foo โดยไม่จำเป็นต้องใช้คุณสมบัติในขณะที่ฉันต้องการเปิดเผยการเข้าถึงผ่านคุณสมบัติใน API เท่านั้น
Kaiserludi

56

C ++ ไม่มีในตัวคุณสามารถกำหนดเทมเพลตเพื่อเลียนแบบคุณสมบัติการทำงาน:

template <typename T>
class Property {
public:
    virtual ~Property() {}  //C++11: use override and =default;
    virtual T& operator= (const T& f) { return value = f; }
    virtual const T& operator() () const { return value; }
    virtual explicit operator const T& () const { return value; }
    virtual T* operator->() { return &value; }
protected:
    T value;
};

ในการกำหนดคุณสมบัติ :

Property<float> x;

ในการใช้getter / setter ที่กำหนดเองเพียงแค่สืบทอด:

class : public Property<float> {
    virtual float & operator = (const float &f) { /*custom code*/ return value = f; }
    virtual operator float const & () const { /*custom code*/ return value; }
} y;

ในการกำหนดคุณสมบัติอ่านอย่างเดียว :

template <typename T>
class ReadOnlyProperty {
public:
    virtual ~ReadOnlyProperty() {}
    virtual operator T const & () const { return value; }
protected:
    T value;
};

และเพื่อใช้ในชั้นเรียนOwner :

class Owner {
public:
    class : public ReadOnlyProperty<float> { friend class Owner; } x;
    Owner() { x.value = 8; }
};

คุณสามารถกำหนดบางส่วนข้างต้นในมาโครเพื่อให้กระชับมากขึ้น


ฉันอยากรู้ว่าการคอมไพล์นี้เป็นคุณลักษณะที่ไม่มีต้นทุนหรือไม่ฉันไม่รู้ว่าการรวมสมาชิกข้อมูลแต่ละตัวในอินสแตนซ์คลาสจะส่งผลให้มีโครงสร้างบรรจุแบบเดียวกันหรือไม่
ได

1
ตรรกะ "getter / setter ที่กำหนดเอง" สามารถสร้างให้มีความสะอาดทางวากยสัมพันธ์ได้โดยใช้ฟังก์ชันแลมบ์ดาน่าเสียดายที่คุณไม่สามารถกำหนดแลมบ์ดานอกบริบทที่ปฏิบัติการได้ใน C ++ (ยัง!) เป็นคนโง่เขลา / setters โง่ซึ่งโชคร้าย
ได

2
"class: ... " ในตัวอย่างสุดท้ายน่าสนใจและขาดหายไปจากตัวอย่างอื่น ๆ สร้างการประกาศเพื่อนที่จำเป็น - โดยไม่ต้องแนะนำชื่อชั้นเรียนใหม่
Hans Olsson

ความแตกต่างอย่างมากระหว่างสิ่งนี้กับคำตอบในปี 2010-19-19 คือสิ่งนี้ช่วยให้สามารถลบล้าง getter หรือ setter ได้เป็นกรณี ๆ ไป ด้วยวิธีนี้เราสามารถตรวจสอบอินพุตให้อยู่ในช่วงหรือส่งการแจ้งเตือนการเปลี่ยนแปลงเพื่อเปลี่ยนผู้ฟังเหตุการณ์หรือสถานที่สำหรับแขวนเบรกพอยต์
Eljay

โปรดทราบว่าสิ่งvirtualนี้อาจไม่จำเป็นสำหรับกรณีการใช้งานส่วนใหญ่เนื่องจากคุณสมบัติไม่น่าจะถูกใช้ในหลายรูปแบบ
Eljay

28

ไม่มีสิ่งใดในภาษา C ++ ที่จะใช้ได้กับทุกแพลตฟอร์มและคอมไพเลอร์

แต่ถ้าคุณยินดีที่จะทำลายความเข้ากันได้ข้ามแพลตฟอร์มและยอมรับคอมไพเลอร์เฉพาะคุณอาจสามารถใช้ไวยากรณ์ดังกล่าวได้เช่นใน Microsoft Visual C ++คุณสามารถทำได้

// declspec_property.cpp  
struct S {  
   int i;  
   void putprop(int j) {   
      i = j;  
   }  

   int getprop() {  
      return i;  
   }  

   __declspec(property(get = getprop, put = putprop)) int the_prop;  
};  

int main() {  
   S s;  
   s.the_prop = 5;  
   return s.the_prop;  
}


18

คุณสามารถเลียนแบบ getter และ setter ได้ในระดับหนึ่งโดยให้สมาชิกประเภททุ่มเทและลบล้างoperator(type)และoperator=เพื่อมัน ไม่ว่าจะเป็นความคิดที่ดีเป็นคำถามอื่นหรือไม่และฉันจะ+1ตอบคำถามของ Kerrek SB เพื่อแสดงความคิดเห็นของฉัน :)


คุณสามารถเลียนแบบการเรียกเมธอดเมื่อกำหนดให้หรืออ่านจากประเภทดังกล่าว แต่คุณไม่สามารถแยกแยะได้ว่าใครเรียกการดำเนินการมอบหมาย (ห้ามมิให้ใช้หากไม่ใช่เจ้าของฟิลด์) - สิ่งที่ฉันกำลังพยายามทำโดยระบุการเข้าถึงที่แตกต่างกัน ระดับสำหรับ getter และ setter
Radim Vansa

@ Flavius: เพียงเพิ่ม a friendให้กับเจ้าของสนาม
kennytm

18

ด้วย C ++ 11 คุณสามารถกำหนดเทมเพลตคลาสคุณสมบัติและใช้งานได้ดังนี้:

class Test{
public:
  Property<int, Test> Number{this,&Test::setNumber,&Test::getNumber};

private:
  int itsNumber;

  void setNumber(int theNumber)
    { itsNumber = theNumber; }

  int getNumber() const
    { return itsNumber; }
};

และนี่คือเทมเพลตคลาสคุณสมบัติ

template<typename T, typename C>
class Property{
public:
  using SetterType = void (C::*)(T);
  using GetterType = T (C::*)() const;

  Property(C* theObject, SetterType theSetter, GetterType theGetter)
   :itsObject(theObject),
    itsSetter(theSetter),
    itsGetter(theGetter)
    { }

  operator T() const
    { return (itsObject->*itsGetter)(); }

  C& operator = (T theValue) {
    (itsObject->*itsSetter)(theValue);
    return *itsObject;
  }

private:
  C* const itsObject;
  SetterType const itsSetter;
  GetterType const itsGetter;
};

2
สิ่งที่ไม่C::*หมายถึง? ฉันไม่เคยเห็นอะไรแบบนี้มาก่อน?
Rika

1
Cมันเป็นตัวชี้ไปยังฟังก์ชันสมาชิกไม่คงที่ในชั้นเรียน สิ่งนี้คล้ายกับตัวชี้ฟังก์ชันธรรมดา แต่ในการเรียกใช้ฟังก์ชันสมาชิกคุณต้องระบุวัตถุที่เรียกใช้ฟังก์ชัน สิ่งนี้ทำได้ด้วยบรรทัดitsObject->*itsSetter(theValue)ในตัวอย่างด้านบน ดูที่นี่สำหรับรายละเอียดเพิ่มเติมของคุณลักษณะนี้
Christoph Böhme

@Niceman มีตัวอย่างการใช้งานหรือไม่? ดูเหมือนว่าจะมีค่าใช้จ่ายสูงมากในการเป็นสมาชิก มันไม่มีประโยชน์อย่างยิ่งในฐานะสมาชิกแบบคงที่เช่นกัน
Grim Fandango

17

อาจลองดูคลาสคุณสมบัติที่ฉันรวบรวมในช่วงชั่วโมงที่แล้ว: /codereview/7786/c11-feedback-on-my-approach-to-c-like-class-properties

ช่วยให้คุณมีคุณสมบัติที่ทำงานเช่นนี้:

CTestClass myClass = CTestClass();

myClass.AspectRatio = 1.4;
myClass.Left = 20;
myClass.Right = 80;
myClass.AspectRatio = myClass.AspectRatio * (myClass.Right - myClass.Left);

อย่างไรก็ตามแม้ว่าสิ่งนี้จะอนุญาตให้ผู้ใช้กำหนดเองได้ แต่ก็ไม่มีคุณสมบัติ getter / private setter ที่ฉันกำลังมองหา
Radim Vansa

16

ดังที่หลายคนได้กล่าวไปแล้วไม่มีการรองรับภาษาในตัว อย่างไรก็ตามหากคุณกำหนดเป้าหมายไปที่คอมไพเลอร์ Microsoft C ++ คุณสามารถใช้ประโยชน์จากส่วนขยายเฉพาะของ Microsoft สำหรับคุณสมบัติที่มีการบันทึกไว้ที่นี่

นี่คือตัวอย่างจากหน้าที่เชื่อมโยง:

// declspec_property.cpp
struct S {
   int i;
   void putprop(int j) { 
      i = j;
   }

   int getprop() {
      return i;
   }

   __declspec(property(get = getprop, put = putprop)) int the_prop;
};

int main() {
   S s;
   s.the_prop = 5;
   return s.the_prop;
}

12

ไม่ C ++ ไม่มีแนวคิดเกี่ยวกับคุณสมบัติ แม้ว่าการกำหนดและเรียก getThis () หรือ setThat (value) อาจเป็นเรื่องที่ไม่สะดวก แต่คุณกำลังแถลงต่อผู้บริโภคเกี่ยวกับวิธีการเหล่านั้นว่าอาจมีฟังก์ชันบางอย่าง ในทางกลับกันการเข้าถึงฟิลด์ใน C ++ จะบอกผู้บริโภคว่าจะไม่มีฟังก์ชันเพิ่มเติมหรือไม่คาดคิดเกิดขึ้น คุณสมบัติจะทำให้สิ่งนี้ชัดเจนน้อยลงเนื่องจากการเข้าถึงคุณสมบัติในแวบแรกดูเหมือนว่าจะตอบสนองเหมือนเขตข้อมูล แต่ในความเป็นจริงจะตอบสนองเหมือนวิธีการ

นอกจากนี้ฉันยังทำงานในแอปพลิเคชัน. NET (CMS ที่รู้จักกันดี) เพื่อสร้างระบบสมาชิกของลูกค้า เนื่องจากวิธีที่พวกเขาใช้คุณสมบัติสำหรับออบเจ็กต์ผู้ใช้ของพวกเขาการดำเนินการจึงเกิดขึ้นโดยที่ฉันไม่คาดคิดทำให้การใช้งานของฉันดำเนินการในรูปแบบที่แปลกประหลาดรวมถึงการเรียกซ้ำที่ไม่สิ้นสุด นี่เป็นเพราะออบเจ็กต์ผู้ใช้ของพวกเขาทำการเรียกชั้นการเข้าถึงข้อมูลหรือระบบแคชส่วนกลางบางระบบเมื่อพยายามเข้าถึงสิ่งง่ายๆเช่น StreetAddress ระบบทั้งหมดของพวกเขาก่อตั้งขึ้นจากสิ่งที่ฉันเรียกว่าการละเมิดคุณสมบัติ หากพวกเขาใช้วิธีการแทนคุณสมบัติฉันคิดว่าฉันจะพบสิ่งที่ผิดพลาดได้เร็วขึ้น หากพวกเขาใช้ฟิลด์ (หรืออย่างน้อยก็ทำให้คุณสมบัติของมันทำงานเหมือนฟิลด์มากขึ้น) ฉันคิดว่าระบบน่าจะขยายและบำรุงรักษาได้ง่ายกว่า

[แก้ไข] เปลี่ยนความคิดของฉัน ฉันมีวันที่เลวร้ายและพูดคุยโวนิดหน่อย การล้างข้อมูลนี้ควรเป็นมืออาชีพมากขึ้น



4

นี่ไม่ใช่คุณสมบัติ แต่ทำในสิ่งที่คุณต้องการด้วยวิธีง่ายๆ:

class Foo {
  int x;
public:
  const int& X;
  Foo() : X(x) {
    ...
  }
};

ที่นี่ X ขนาดใหญ่จะทำงานเหมือนpublic int X { get; private set; }ในไวยากรณ์ C # หากคุณต้องการคุณสมบัติเต็มเป่าผมทำยิงครั้งแรกจะใช้พวกเขาที่นี่


2
นี่ไม่ใช่ความคิดที่ดี เมื่อใดก็ตามที่คุณทำสำเนาของออบเจ็กต์ของคลาสนี้การอ้างอิงXของอ็อบเจ็กต์ใหม่จะยังคงชี้ไปที่สมาชิกของอ็อบเจ็กต์เก่าเนื่องจากมันถูกคัดลอกเหมือนกับสมาชิกพอยน์เตอร์ สิ่งนี้ไม่ดีในตัวเอง แต่เมื่อวัตถุเก่าถูกลบคุณจะได้รับความเสียหายของหน่วยความจำที่อยู่ด้านบน ในการทำงานนี้คุณจะต้องใช้ตัวสร้างการคัดลอกตัวดำเนินการกำหนดและตัวสร้างการย้ายของคุณเอง
toster

4

คุณอาจจะรู้ แต่ฉันจะทำสิ่งต่อไปนี้:

class Person {
public:
    std::string name() {
        return _name;
    }
    void name(std::string value) {
        _name = value;
    }
private:
    std::string _name;
};

วิธีนี้ง่ายไม่ต้องใช้เทคนิคที่ชาญฉลาดและทำให้งานสำเร็จ!

แม้ว่าปัญหาคือบางคนไม่ชอบที่จะนำเขตข้อมูลส่วนตัวของตนด้วยเครื่องหมายขีดล่างดังนั้นพวกเขาจึงไม่สามารถใช้แนวทางนี้ได้ แต่โชคดีสำหรับคนเหล่านี้ที่ทำมันตรงไปตรงมาจริงๆ :)

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

อีกอย่างหนึ่งคือง่ายที่จะเข้าใจว่านี่คือคุณสมบัติเพราะnameไม่ใช่คำกริยา

สถานการณ์ที่เลวร้ายที่สุดหาก API มีความสอดคล้องกันและบุคคลนั้นไม่ทราบว่าname()เป็น accessor และname(value)เป็นผู้กลายพันธุ์เธอจะต้องค้นหาเพียงครั้งเดียวในเอกสารเพื่อทำความเข้าใจกับรูปแบบ

เท่าที่ฉันรัก C # ฉันไม่คิดว่า C ++ ต้องการคุณสมบัติเลย!


ผู้กลายพันธุ์ของคุณมีเหตุผลหากมีคนใช้foo(bar)(แทนที่จะเป็นตัวช้ากว่าfoo = bar) แต่ตัวเข้าถึงของคุณไม่มีส่วนเกี่ยวข้องกับคุณสมบัติเลย ...
Matthias

@Matthias ระบุว่าไม่เกี่ยวอะไรกับสรรพคุณเลยไม่บอกรายละเอียดได้ไหม? นอกจากนี้ฉันไม่ได้พยายามเปรียบเทียบ แต่ถ้าคุณต้องการ mutator และ accessor คุณสามารถใช้หลักการนี้ได้
Eyal Solnik

คำถามเกี่ยวกับแนวคิดซอฟต์แวร์ของ Properties คุณสมบัติสามารถใช้ได้ราวกับว่าเป็นสมาชิกข้อมูลสาธารณะ (การใช้งาน) แต่จริงๆแล้วเป็นวิธีการพิเศษที่เรียกว่า accessors (การประกาศ) โซลูชันของคุณยึดติดกับวิธีการ (getters / setters ธรรมดา) สำหรับการประกาศและการใช้งาน ดังนั้นนี่คือประการแรกไม่ใช่การใช้งานที่ OP ขอ แต่เป็นหลักการตั้งชื่อที่แปลกและไม่เป็นทางการ (และประการที่สองไม่มีน้ำตาลที่เป็นประโยคด้วย)
Matthias

ในฐานะที่เป็นผลข้างเคียงเล็กน้อย mutator ของคุณทำงานเป็นคุณสมบัติได้อย่างน่าประหลาดใจเนื่องจากใน C ++ สิ่งหนึ่งที่ดีที่สุดเริ่มต้นด้วยfoo(bar)แทนfoo=barซึ่งสามารถทำได้ด้วยvoid foo(Bar bar)วิธีการกลายพันธุ์ใน_fooตัวแปรสมาชิก
Matthias

@ Matthias ฉันรู้ว่าคุณสมบัติคืออะไรฉันเขียน C ++ ค่อนข้างน้อยและ C # มานานกว่าทศวรรษฉันไม่ได้เถียงเกี่ยวกับประโยชน์ของคุณสมบัติและสิ่งที่พวกเขาเป็น แต่ฉันไม่เคยต้องการมันใน C ++ จริงๆแล้วคุณ กล่าวว่าสามารถใช้เป็นข้อมูลสาธารณะได้และส่วนใหญ่เป็นความจริง แต่มีบางกรณีใน C # ที่คุณไม่สามารถใช้คุณสมบัติได้โดยตรงเช่นการส่งคุณสมบัติโดยการอ้างอิงในขณะที่คุณสามารถใช้ฟิลด์สาธารณะได้
Eyal Solnik

4

ไม่ .. แต่คุณควรพิจารณาว่ามันเป็นเพียงแค่ get: set function และไม่มีงานเพิ่มเติมใด ๆ ที่สร้างไว้แล้วภายใน get: set method เพียงแค่ทำให้เป็นสาธารณะ


2

ฉันรวบรวมแนวคิดจากแหล่งที่มาของ C ++ หลายแหล่งและนำไปใช้เป็นตัวอย่างที่ดี แต่ค่อนข้างง่ายสำหรับ getters / setters ใน C ++:

class Canvas { public:
    void resize() {
        cout << "resize to " << width << " " << height << endl;
    }

    Canvas(int w, int h) : width(*this), height(*this) {
        cout << "new canvas " << w << " " << h << endl;
        width.value = w;
        height.value = h;
    }

    class Width { public:
        Canvas& canvas;
        int value;
        Width(Canvas& canvas): canvas(canvas) {}
        int & operator = (const int &i) {
            value = i;
            canvas.resize();
            return value;
        }
        operator int () const {
            return value;
        }
    } width;

    class Height { public:
        Canvas& canvas;
        int value;
        Height(Canvas& canvas): canvas(canvas) {}
        int & operator = (const int &i) {
            value = i;
            canvas.resize();
            return value;
        }
        operator int () const {
            return value;
        }
    } height;
};

int main() {
    Canvas canvas(256, 256);
    canvas.width = 128;
    canvas.height = 64;
}

เอาท์พุต:

new canvas 256 256
resize to 128 256
resize to 128 64

คุณสามารถทดสอบออนไลน์ได้ที่นี่: http://codepad.org/zosxqjTX


มีค่าใช้จ่ายของหน่วยความจำในการรักษาการอ้างอิงตัวเอง + ไวยากรณ์ ctor ที่น่าอึดอัดใจ
Red.Wave

เพื่อเสนอคุณสมบัติ? ฉันเดาว่ามีข้อเสนอมากมายที่ถูกปฏิเสธ
Red Wave

@ เร้ดเวฟก้มหัวให้เจ้านายและเจ้าแห่งการปฏิเสธแล้ว ยินดีต้อนรับสู่ C ++ เสียงดังและ MSVC มีส่วนขยายที่กำหนดเองสำหรับคุณสมบัติหากคุณไม่ต้องการให้มีการอ้างอิงด้วยตนเอง
kungfooman

ฉันไม่สามารถโค้งคำนับ ไม่ใช่ทุกคุณสมบัติที่ฉันคิดว่าเหมาะสม สำหรับฉัน Objects เป็นมากกว่าฟังก์ชัน setter + getter ฉันได้ลองใช้งานของตัวเองเพื่อหลีกเลี่ยงค่าใช้จ่ายของหน่วยความจำถาวรที่ไม่จำเป็น แต่ไวยากรณ์และงานที่น่าเบื่อของการประกาศอินสแตนซ์ไม่น่าพอใจ ฉันชอบใช้มาโครที่เปิดเผย แต่ฉันไม่ใช่แฟนตัวยงของมาโคร แต่อย่างใด และในที่สุดแนวทางของฉันก็นำไปสู่ ​​porperties ที่เข้าถึงด้วยไวยากรณ์ของฟังก์ชันซึ่งหลายคนรวมถึงตัวฉันเองไม่เห็นด้วย
Red.Wave

0

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


0

มีชุดของแมโครที่เขียนอยู่นี่ มีการประกาศคุณสมบัติที่น่าเชื่อถือสำหรับประเภทค่าประเภทอ้างอิงประเภทอ่านอย่างเดียวประเภทที่แข็งแกร่งและอ่อนแอ

class MyClass {

 // Use assign for value types.
 NTPropertyAssign(int, StudentId)

 public:
 ...

}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.