คุณจะสร้างคลาสแบบคงที่ใน C ++ ได้อย่างไร


263

คุณจะสร้างคลาสแบบคงที่ใน C ++ ได้อย่างไร ฉันควรจะทำสิ่งที่ชอบ:

cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;

สมมติว่าฉันสร้างBitParserชั้นเรียน BitParserคำจำกัดความของคลาสจะเป็นอย่างไร


198
อ๋อ ย้อนกลับไปในสมัยก่อนเราเพิ่งเรียกมันว่า "ฟังก์ชั่น" คุณเป็นเด็กวันนี้ด้วย "namespaces" ที่บ้าของคุณ เฮ้ลงสนามหญ้าของฉันสิ! <สั่นกำปั้น>
จรจัด

7
@Vagrant ฟังก์ชันภายในเนมสเปซยังคงเป็นฟังก์ชัน ฟังก์ชั่นที่เป็นของคลาสเรียกว่าเมธอด ถ้ามันเป็นวิธีการคงที่คุณเรียกมันคล้ายกับว่ามันเป็นฟังก์ชั่นภายใน namespace

48
5 ปีต่อมาและตอนนี้ฉันเข้าข้าง @Vagrant เป็นคำถามที่โง่!
andrewrk

16
9 ปีต่อมาและตอนนี้ฉันมีภาษาการเขียนโปรแกรมของตัวเองที่ไม่ได้มีชั้นเรียน: ziglang.org
andrewrk

1
IMO คลาสที่คล้ายกับคอนเทนเนอร์ (มีเมธอดแบบสแตติก) มีประโยชน์ในบางกรณี
AarCee

คำตอบ:


272

หากคุณกำลังมองหาวิธีการใช้คำหลัก "คงที่" กับคลาสเช่นคุณสามารถใน C # ตัวอย่างเช่นคุณจะไม่สามารถโดยไม่ต้องใช้ C ++ ที่มีการจัดการ

แต่ลักษณะตัวอย่างของคุณคุณเพียงแค่ต้องสร้างวิธีการคงที่สาธารณะในวัตถุ BitParser ของคุณ ชอบมาก

BitParser.h

class BitParser
{
 public:
  static bool getBitAt(int buffer, int bitIndex);

  // ...lots of great stuff

 private:
  // Disallow creating an instance of this object
  BitParser() {}
};

BitParser.cpp

bool BitParser::getBitAt(int buffer, int bitIndex)
{
  bool isBitSet = false;
  // .. determine if bit is set
  return isBitSet;
}

คุณสามารถใช้รหัสนี้เพื่อเรียกใช้วิธีการเช่นเดียวกับรหัสตัวอย่างของคุณ

หวังว่าจะช่วย! ไชโย


2
OJ คุณมีข้อผิดพลาดทางไวยากรณ์ คีย์เวิร์ดสแตติกควรใช้ในการกำหนดคลาสเท่านั้นและไม่ควรอยู่ในนิยามเมธอด
andrewrk

90
เพื่อให้ความตั้งใจของคุณชัดเจนในวิธีนี้คุณสามารถใช้ตัวสร้างส่วนบุคคลเพิ่มเติมได้ private: BitParser() {}สิ่งนี้จะป้องกันไม่ให้ใครสร้างอินสแตนซ์
Danvil

7
@MoatazElmasry ความปลอดภัยของเธรดเป็นปัญหาเมื่อคุณแชร์สถานะ ในการดำเนินการข้างต้นไม่มีสถานะที่ใช้ร่วมกันดังนั้นจึงไม่มีปัญหาใด ๆ กับความปลอดภัยของเธรด ... เว้นแต่คุณจะโง่พอที่จะใช้สถิตยศาสตร์ในฟังก์ชั่นเหล่านั้น ใช่รหัสข้างบนนี้ปลอดภัยสำหรับเธรดเพียงแค่คงสถานะการทำงานของคุณเอาไว้และคุณก็ทำได้ดี
OJ

@MoatazElmasry ไม่ถูกต้อง สองเธรดไม่สามารถแก้ไขตัวแปรภายในที่ไม่คงที่ในฟังก์ชันคงที่
OJ

12
ถ้า C ++ 11 ฉันจะเถียงว่าเป็นการดีกว่าที่BitParser() = delete;จะสื่อความตั้งใจที่จะลบนวกรรมิก (ไม่ใช่เพียงซ่อนไว้private)
ฟีนิกซ์

247

พิจารณาวิธีการแก้ปัญหาของแมตต์ราคา

  1. ใน C ++ หมายถึง "คลาสคงที่" ไม่มีความหมาย สิ่งที่ใกล้ที่สุดคือชั้นเรียนที่มีวิธีการคงที่และสมาชิกเท่านั้น
  2. การใช้วิธีการคงที่จะ จำกัด คุณเท่านั้น

สิ่งที่คุณต้องการคือแสดงในซีแมนทิกส์ C ++ เพื่อใส่ฟังก์ชั่นของคุณ (เพราะมันเป็นฟังก์ชั่น) ในเนมสเปซ

แก้ไข 2011-11-11

ไม่มี "คลาสคงที่" ใน C ++ แนวคิดที่ใกล้ที่สุดจะเป็นคลาสที่มีวิธีการคงที่เท่านั้น ตัวอย่างเช่น:

// header
class MyClass
{
   public :
      static void myMethod() ;
} ;

// source
void MyClass::myMethod()
{
   // etc.
}

แต่คุณต้องจำไว้ว่า "คลาสคงที่" เป็นแฮ็คในภาษาที่มีลักษณะคล้าย Java (เช่น C #) ที่ไม่สามารถมีฟังก์ชั่นที่ไม่ได้เป็นสมาชิกดังนั้นพวกเขาจึงต้องย้ายพวกมันเข้าไปในคลาส

ใน C ++ สิ่งที่คุณต้องการจริงๆคือฟังก์ชั่นที่ไม่ใช่สมาชิกที่คุณจะประกาศในเนมสเปซ:

// header
namespace MyNamespace
{
   void myMethod() ;
}

// source
namespace MyNamespace
{
   void myMethod()
   {
      // etc.
   }
}

ทำไมถึงเป็นอย่างนั้น?

ใน C ++ เนมสเปซมีประสิทธิภาพมากกว่าคลาสสำหรับรูปแบบ "Java static method" เนื่องจาก:

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

บทสรุป: อย่าคัดลอก / วางรูปแบบของ Java / C # ใน C ++ ใน Java / C # รูปแบบจำเป็นต้องมี แต่ใน C ++ มันเป็นสไตล์ที่ไม่ดี

แก้ไข 2010-06-10

มีข้อโต้แย้งในความโปรดปรานของวิธีการแบบคงที่เพราะบางครั้งหนึ่งต้องใช้ตัวแปรสมาชิกส่วนตัวคงที่

ฉันไม่เห็นด้วยบ้างดังแสดงด้านล่าง:

โซลูชัน "สมาชิกส่วนตัวคงที่"

// HPP

class Foo
{
   public :
      void barA() ;
   private :
      void barB() ;
      static std::string myGlobal ;
} ;

อย่างแรก myGlobal เรียกว่า myGlobal เพราะมันยังคงเป็นตัวแปรส่วนบุคคลระดับโลก ดูที่แหล่ง CPP จะชี้แจงว่า:

// CPP
std::string Foo::myGlobal ; // You MUST declare it in a CPP

void Foo::barA()
{
   // I can access Foo::myGlobal
}

void Foo::barB()
{
   // I can access Foo::myGlobal, too
}

void barC()
{
   // I CAN'T access Foo::myGlobal !!!
}

เมื่อแรกพบข้อเท็จจริงที่ว่าฟังก์ชั่นฟรี barC ไม่สามารถเข้าถึง Foo :: myGlobal ดูเหมือนจะเป็นสิ่งที่ดีจากจุดชมวิวแบบห่อหุ้ม ... มันเจ๋งมากเพราะมีคนดู HPP จะไม่สามารถเข้าถึงได้ (เว้นแต่จะหันไปก่อวินาศกรรม) foo :: myGlobal

แต่ถ้าคุณมองอย่างใกล้ชิดคุณจะพบว่ามันเป็นความผิดพลาดที่ยิ่งใหญ่: ไม่เพียง แต่ตัวแปรส่วนตัวของคุณจะต้องยังคงถูกประกาศใน HPP (และอื่น ๆ ที่มองเห็นได้ทั่วโลกแม้จะเป็นส่วนตัว) แต่คุณต้องประกาศ ในฟังก์ชั่น HPP เดียวกันทั้งหมด (เหมือนในทั้งหมด) ที่จะได้รับอนุญาตให้เข้าถึง !!!

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

private แน่นอน ... :-D

วิธีแก้ปัญหา "Anonymous namespaces"

เนมสเปซที่ไม่ระบุชื่อจะมีข้อได้เปรียบในการทำสิ่งที่เป็นส่วนตัวอย่างแท้จริง

ครั้งแรกที่ส่วนหัว HPP

// HPP

namespace Foo
{
   void barA() ;
}

เพียงเพื่อให้แน่ใจว่าคุณพูด: ไม่มีการประกาศ barB หรือ myGlobal ที่ไร้ประโยชน์ ซึ่งหมายความว่าไม่มีใครอ่านส่วนหัวจะรู้ว่ามีอะไรซ่อนอยู่หลัง barA

จากนั้น CPP:

// CPP
namespace Foo
{
   namespace
   {
      std::string myGlobal ;

      void Foo::barB()
      {
         // I can access Foo::myGlobal
      }
   }

   void barA()
   {
      // I can access myGlobal, too
   }
}

void barC()
{
   // I STILL CAN'T access myGlobal !!!
}

อย่างที่คุณเห็นเช่นเดียวกับการประกาศ "คลาสคงที่" fooA และ fooB ยังสามารถเข้าถึง myGlobal ได้ แต่ไม่มีใครสามารถทำได้ และไม่มีใครอื่นนอก CPP นี้รู้ว่า fooB และ myGlobal ยังคงมีอยู่!

ซึ่งแตกต่างจาก "ระดับคงที่" เดินบนเปลือยกับสมุดที่อยู่ของเธอมีรอยสักบนผิวหนังของเธอ "ไม่ระบุชื่อ" namespace ห่มอย่างเต็มที่ซึ่งดูเหมือนว่าค่อนข้างดีกว่าที่ห่อหุ้ม AFAIK

มันสำคัญจริงๆหรือ

เว้นแต่ผู้ใช้รหัสของคุณต้องโทษ (ฉันจะให้คุณเช่นการออกกำลังกายพบว่าวิธีการหนึ่งที่สามารถเข้าถึงไปยังส่วนส่วนตัวของคลาสที่สาธารณะโดยใช้สับพฤติกรรมที่ไม่ได้กำหนดสกปรก ... ), สิ่งที่privateเป็นprivateถึงแม้ว่ามันจะ สามารถมองเห็นได้ในprivateส่วนของคลาสที่ประกาศในส่วนหัว

ถึงกระนั้นหากคุณต้องการเพิ่ม "ฟังก์ชั่นส่วนตัว" อีกอันที่สามารถเข้าถึงสมาชิกส่วนตัวคุณยังต้องประกาศให้ทุกคนในโลกเห็นด้วยการแก้ไขหัวข้อซึ่งเป็นความขัดแย้งเท่าที่ฉันกังวล: ถ้าฉันเปลี่ยนการใช้งานของ รหัสของฉัน (ส่วน CPP) จากนั้นส่วนต่อประสาน (ส่วน HPP) ไม่ควรเปลี่ยนแปลง การอ้างถึง Leonidas: " นี่คือการทำนาย! "

แก้ไข 2014-09-20

คลาสแบบสแตติกเมธอดจะดีกว่าเนมสเปซที่มีฟังก์ชั่นที่ไม่ใช่สมาชิกเมื่อใด

เมื่อคุณต้องการจัดกลุ่มฟังก์ชั่นร่วมกันและฟีดกลุ่มนั้นไปยังแม่แบบ

namespace alpha
{
   void foo() ;
   void bar() ;
}

struct Beta
{
   static void foo() ;
   static void bar() ;
};

template <typename T>
struct Gamma
{
   void foobar()
   {
      T::foo() ;
      T::bar() ;
   }
};

Gamma<alpha> ga ; // compilation error
Gamma<Beta> gb ;  // ok
gb.foobar() ;     // ok !!!

เนื่องจากถ้าคลาสสามารถเป็นพารามิเตอร์เทมเพลตเนมสเปซไม่สามารถทำได้


3
GCC รองรับ -fno-access-control ซึ่งสามารถใช้ในการทดสอบหน่วย whitebox เพื่อเข้าถึงสมาชิกชั้นเรียนส่วนตัว นั่นเป็นเหตุผลเดียวที่ฉันสามารถคิดว่าจะแสดงให้เห็นถึงการใช้สมาชิกชั้นเรียนแทนการใช้แบบไม่ระบุชื่อ / แบบโกลบอลในการนำไปใช้
Tom

8
@Tom: โซลูชันข้ามแพลตฟอร์มจะเพิ่มรหัสต่อไปนี้#define private publicในส่วนหัว ... ^ _ ^ ...
paercebal

1
@ ทอม: อย่างไรก็ตาม IMHO แม้พิจารณาการทดสอบหน่วยข้อเสียของ "การแสดงสิ่งที่มากเกินไป" มีค่ามากกว่าข้อดี ฉันเดาวิธีแก้ปัญหาทางเลือกคือการใส่รหัสที่จะทดสอบในฟังก์ชั่นรับพารามิเตอร์ที่จำเป็น (และไม่มาก) ในutilitiesnamespace ด้วยวิธีนี้ฟังก์ชั่นนี้สามารถทดสอบหน่วยและยังไม่สามารถเข้าถึงสมาชิกส่วนตัว (ตามที่ได้รับเป็นพารามิเตอร์ในการเรียกใช้ฟังก์ชัน) ...
paercebal

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

@ แซค: แน่นอนพวกเขาทำได้ แต่ลองทำในไฟล์ CPP ที่มีการประกาศตัวแปร myGlobal ประเด็นคือทัศนวิสัยมากกว่าการเข้าถึง ในคลาสสแตติกตัวแปร myGlobal เป็นแบบส่วนตัว แต่ยังคงมองเห็นได้ สิ่งนี้ไม่สำคัญอย่างที่เห็น แต่ใน DLL แสดงสัญลักษณ์ที่ควรเป็นส่วนตัวกับ DLL ในส่วนหัวที่ถูกส่งออกอาจจะน่าอึดอัดใจ ... ในเนมสเปซ myGlobal จะมีอยู่ในไฟล์ CPP เท่านั้น (คุณ สามารถไปได้ไกลขึ้นและทำให้มันคงที่) ตัวแปรนั้นไม่ปรากฏในส่วนหัวสาธารณะ
paercebal

63

คุณยังสามารถสร้างฟังก์ชั่นฟรีใน namespace:

ใน BitParser.h

namespace BitParser
{
    bool getBitAt(int buffer, int bitIndex);
}

ใน BitParser.cpp

namespace BitParser
{
    bool getBitAt(int buffer, int bitIndex)
    {
        //get the bit :)
    }
}

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


1
ในบางกรณีคุณอาจต้องการให้มีการห่อหุ้มข้อมูลแม้ว่าคลาสนั้นส่วนใหญ่จะ "คงที่" สมาชิกชั้นเรียนส่วนตัวจะให้สิ่งนี้แก่คุณ สมาชิกเนมสเปซจะเปิดเผยต่อสาธารณะเสมอและไม่สามารถให้การห่อหุ้มข้อมูลได้
Torleif

หาก var "member" ถูกประกาศและเข้าถึงจากไฟล์. cpp เท่านั้นจะมีความเป็นส่วนตัวมากกว่า var ส่วนตัวที่ประกาศในไฟล์. h ไม่ใช่ว่าฉันแนะนำเทคนิคนี้
jmucchiello

3
@Torleif: คุณผิด เนมสเปซดีกว่าสำหรับการห่อหุ้มมากกว่าสมาชิกส่วนตัวคงที่ ดูคำตอบของฉันสำหรับการสาธิต
paercebal

1
ใช่ แต่ในเนมสเปซคุณจะต้องรักษาลำดับการทำงานในทางตรงกันข้ามกับคลาสที่มีสมาชิกแบบคงที่ตัวอย่างเช่นโมฆะ a () {b ();} b () {} จะทำให้เกิดข้อผิดพลาดในเนมสเปซ สมาชิกคงที่
Moataz Elmasry

13

หากคุณกำลังมองหาวิธีการใช้คำหลัก "คงที่" กับชั้นเรียนเช่นคุณสามารถใน C #

คลาสสแตติกเป็นเพียงคอมไพเลอร์ที่จับคุณไว้และหยุดคุณจากการเขียนเมธอด / ตัวแปรใด ๆ

หากคุณเพิ่งเขียนคลาสปกติโดยไม่มีเมธอด / ตัวแปรใด ๆ มันก็เหมือนกันและนี่คือสิ่งที่คุณต้องการใน C ++


ที่จะไม่บ่น (โดยเฉพาะอย่างยิ่งที่คุณ) แต่บางคนรวบรวมมือถือเพื่อป้องกันไม่ให้ฉันเขียนหรือตัด / วางคำstatic200 ครั้งจะเป็นสิ่งที่ดี
3Dave

เห็นด้วย - แต่คลาสสแตติกใน C # ไม่ได้ทำเช่นนี้ มันไม่สามารถคอมไพล์ได้เมื่อคุณลืมที่จะวาง static ในนั่น :-)
Orion Edwards

ใช่ - ยุติธรรมเพียงพอ มาโครของฉันกำลังแสดง สุจริตถ้าฉันประกาศคลาสเป็นแบบคงที่คอมไพเลอร์ควรโยนข้อผิดพลาดถ้าฉันพยายามที่จะยกตัวอย่างมัน กฎที่ทำให้ฉันต้องทำซ้ำตัวเองน่ารังเกียจและควรเป็นคนแรกที่ต่อต้านกำแพงเมื่อการปฏิวัติเกิดขึ้น
3Dave

11

ใน C ++ คุณต้องการสร้างฟังก์ชันคงที่ของคลาส (ไม่ใช่คลาสแบบสแตติก)

class BitParser {
public:
  ...
  static ... getBitAt(...) {
  }
};

จากนั้นคุณควรจะสามารถเรียกใช้ฟังก์ชันโดยใช้ BitParser :: getBitAt () โดยไม่ต้องสร้างวัตถุที่ฉันคิดว่าเป็นผลลัพธ์ที่ต้องการ


11

ฉันสามารถเขียนบางอย่างได้static classไหม

ไม่เป็นไปตามร่างมาตรฐาน C ++ 11 N3337ภาคผนวก C 7.1.1:

เปลี่ยนแปลง: ใน C ++ ตัวระบุแบบคงที่หรือภายนอกสามารถใช้กับชื่อของวัตถุหรือฟังก์ชั่นเท่านั้น การใช้ตัวระบุเหล่านี้พร้อมการประกาศประเภทนั้นผิดกฎหมายใน C ++ ใน C ตัวระบุเหล่านี้จะถูกละเว้นเมื่อใช้กับการประกาศชนิด ตัวอย่าง:

static struct S {    // valid C, invalid in C++
  int i;
};

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

และชอบstruct, classนอกจากนี้ยังมีการประกาศประเภท

สามารถอนุมานได้ด้วยการเดินทรีไวยากรณ์ในภาคผนวก A

เป็นที่น่าสนใจที่จะทราบว่าstatic structถูกกฎหมายใน C แต่ไม่มีผล: ทำไมและเมื่อใดจึงจะใช้โครงสร้างแบบคงที่ในการเขียนโปรแกรม C?


6

ตามที่ได้รับการบันทึกไว้ที่นี่วิธีที่ดีกว่าในการบรรลุสิ่งนี้ใน C ++ อาจใช้เนมสเปซ แต่เนื่องจากไม่มีใครพูดถึงfinalคำสำคัญที่นี่ฉันโพสต์สิ่งที่เทียบเท่าโดยตรงstatic classจาก C # จะมีลักษณะเช่นใน C ++ 11 หรือใหม่กว่า:

class BitParser final
{
public:
  BitParser() = delete;

  static bool GetBitAt(int buffer, int pos);
};

bool BitParser::GetBitAt(int buffer, int pos)
{
  // your code
}

5

คุณ 'สามารถ' มีคลาสแบบคงที่ใน C ++ ตามที่กล่าวไว้ก่อนหน้าคลาสแบบสแตติกเป็นคลาสที่ไม่มีวัตถุใด ๆ ใน C ++ สิ่งนี้สามารถรับได้โดยการประกาศตัวสร้าง / destructor เป็นส่วนตัว ผลลัพธ์ที่ได้ก็เหมือนกัน


สิ่งที่คุณแนะนำอาจสร้างคลาสแบบซิงเกิล แต่ไม่เหมือนกับคลาสแบบสแตติก
ksinkar

4

ใน C ++ ที่มีการจัดการไวยากรณ์คลาสคงที่คือ: -

public ref class BitParser abstract sealed
{
    public:
        static bool GetBitAt(...)
        {
            ...
        }
}

... มาสายดีกว่าไม่มาเลย...


3

ซึ่งคล้ายกับวิธีการทำ C # ใน C ++

ใน C # file.cs คุณสามารถมี var ส่วนตัวภายในฟังก์ชั่นสาธารณะ เมื่ออยู่ในไฟล์อื่นคุณสามารถใช้มันได้โดยการเรียก namespace พร้อมกับฟังก์ชั่นดังต่อไปนี้:

MyNamespace.Function(blah);

นี่คือวิธีการเหมือนกันใน C ++:

SharedModule.h

class TheDataToBeHidden
{
  public:
    static int _var1;
    static int _var2;
};

namespace SharedData
{
  void SetError(const char *Message, const char *Title);
  void DisplayError(void);
}

SharedModule.cpp

//Init the data (Link error if not done)
int TheDataToBeHidden::_var1 = 0;
int TheDataToBeHidden::_var2 = 0;


//Implement the namespace
namespace SharedData
{
  void SetError(const char *Message, const char *Title)
  {
    //blah using TheDataToBeHidden::_var1, etc
  }

  void DisplayError(void)
  {
    //blah
  }
}

OtherFile.h

#include "SharedModule.h"

OtherFile.cpp

//Call the functions using the hidden variables
SharedData::SetError("Hello", "World");
SharedData::DisplayError();

2
แต่ทุกคนไปที่ TheDataToBeHidden -> มันไม่ใช่ทางออก
Guy L

3

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


0

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

class Class {
 public:
  void foo() { Static::bar(*this); }    

 private:
  int member{0};
  friend class Static;
};    

class Static {
 public:
  template <typename T>
  static void bar(T& t) {
    t.member = 1;
  }
};

0

ทางเลือกหนึ่ง (จากหลาย ๆ ทาง) แต่ที่สุด (ในความคิดของฉัน) ที่สง่างาม (เมื่อเทียบกับการใช้เนมสเปซและคอนสตรัคเตอร์ส่วนตัวเพื่อเลียนแบบพฤติกรรมแบบคงที่) วิธีการบรรลุพฤติกรรม "คลาสที่ไม่สามารถสร้างอินสแตนซ์ ประกาศฟังก์ชั่นเสมือนจริงที่จำลองด้วยprivateตัวดัดแปลงการเข้าถึง

class Foo {
   public:
     static int someMethod(int someArg);

   private:
     virtual void __dummy() = 0;
};

หากคุณใช้ C ++ 11 คุณสามารถไปที่ไมล์พิเศษเพื่อให้แน่ใจว่าคลาสไม่ได้รับการสืบทอด (เพื่อเลียนแบบพฤติกรรมของคลาสแบบสแตติก) โดยใช้ตัวfinalระบุในการประกาศคลาสเพื่อ จำกัด คลาสอื่นจากการสืบทอดคลาสนั้น .

// C++11 ONLY
class Foo final {
   public:
     static int someMethod(int someArg);

   private:
      virtual void __dummy() = 0;
};

โง่และไร้เหตุผลอย่างที่มันฟังดู C ++ 11 อนุญาตให้ประกาศ "ฟังก์ชั่นเสมือนบริสุทธิ์ที่ไม่สามารถแทนที่" ซึ่งคุณสามารถใช้ควบคู่ไปกับการประกาศชั้นเรียนfinalเพื่อให้เกิดพฤติกรรมแบบคงที่ได้อย่างหมดจด ชั้นเรียนที่จะไม่สามารถสืบทอดได้และฟังก์ชั่นหุ่นที่จะไม่ถูกแทนที่ในทางใดทางหนึ่ง

// C++11 ONLY
class Foo final {
   public:
     static int someMethod(int someArg);

   private:
     // Other private declarations

     virtual void __dummy() = 0 final;
}; // Foo now exhibits all the properties of a static class
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.