ค่าคงที่สุดท้ายเทียบกับ C ++ ของ Java


151

Java สำหรับการเขียนโปรแกรมภาษา C ++ กวดวิชากล่าวว่า (ไฮไลท์เป็นของตัวเอง):

สุดท้ายคำหลักคือประมาณ เทียบเท่ากับ const ใน C ++

"คร่าวๆ" หมายความว่าอะไรในบริบทนี้ พวกเขาไม่เหมือนกันหรือ

อะไรคือความแตกต่างถ้ามี?

คำตอบ:


195

ในการทำเครื่องหมาย C ++ ฟังก์ชันสมาชิกconstหมายความว่ามันอาจถูกเรียกใช้ในconstอินสแตนซ์ Java ไม่เทียบเท่ากับสิ่งนี้ เช่น:

class Foo {
public:
   void bar();
   void foo() const;
};

void test(const Foo& i) {
   i.foo(); //fine
   i.bar(); //error
}

สามารถกำหนดค่าได้หนึ่งครั้งต่อมาใน Java เท่านั้นเช่น:

public class Foo {
   void bar() {
     final int a;
     a = 10;
   }
}

ถูกกฎหมายใน Java แต่ไม่ใช่ C ++ ในขณะที่:

public class Foo {
   void bar() {
     final int a;
     a = 10;
     a = 11; // Not legal, even in Java: a has already been assigned a value.
   }
}

ทั้งในตัวแปรสมาชิก Java และ C ++ อาจเป็นfinal/ constตามลำดับ จำเป็นต้องได้รับค่าตามเวลาที่อินสแตนซ์ของคลาสเสร็จสิ้นการสร้าง

ใน Java จะต้องตั้งค่าก่อนที่ตัวสร้างจะเสร็จสิ้นซึ่งสามารถทำได้ในหนึ่งในสองวิธี:

public class Foo {
   private final int a;
   private final int b = 11;
   public Foo() {
      a = 10;
   }
}

ใน C ++ คุณจะต้องใช้รายการเริ่มต้นเพื่อให้constค่าสมาชิก:

class Foo {
   const int a;
public:
   Foo() : a(10) {
      // Assignment here with = would not be legal
   }
};

ใน Java ขั้นสุดท้ายสามารถใช้เพื่อทำเครื่องหมายสิ่งต่าง ๆ ว่าไม่สามารถ overridable C ++ (pre-C ++ 11) ไม่ได้ทำเช่นนี้ เช่น:

public class Bar {
   public final void foo() {
   }
}

public class Error extends Bar {
   // Error in java, can't override
   public void foo() {
   }
}

แต่ใน C ++:

class Bar {
public:
   virtual void foo() const {
   }
};

class Error: public Bar {
public:
   // Fine in C++
   virtual void foo() const {
   }
};

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


การอัปเดต C ++ 11:

ในความเป็นจริง C ++ 11 ช่วยให้คุณสามารถทำเครื่องหมายทั้งคลาสและฟังก์ชันสมาชิกfinalด้วยความหมายเหมือนกันกับคุณลักษณะเดียวกันใน Java ตัวอย่างเช่นใน Java:

public class Bar {
   public final void foo() {
   }
}

public class Error extends Bar {
   // Error in java, can't override
   public void foo() {
   }
}

ตอนนี้สามารถเขียนตรงใน C ++ 11 เป็น:

class Bar {
public:
  virtual void foo() final;
};

class Error : public Bar {
public:
  virtual void foo() final;
};

ฉันต้องรวบรวมตัวอย่างนี้ด้วยการเปิดตัว G ++ 4.7 ล่วงหน้า โปรดทราบว่าสิ่งนี้ไม่ได้แทนที่constในกรณีนี้ แต่เป็นการเพิ่มให้มันเป็นพฤติกรรมที่คล้ายกับจาวาที่ไม่เห็นด้วยคำสำคัญ C ++ ที่ใกล้เคียงที่สุด ดังนั้นหากคุณต้องการให้ฟังก์ชันสมาชิกเป็นทั้งสองอย่างfinalและconstคุณจะทำดังนี้

class Bar {
public:
  virtual void foo() const final;
};

( จำเป็นต้องมีคำสั่งซื้อconstและfinalที่นี่)

ก่อนหน้านี้ไม่มีconstฟังก์ชั่นสมาชิกเทียบเท่าโดยตรงแม้ว่าการทำฟังก์ชั่นที่ไม่ใช่virtualจะเป็นตัวเลือกที่มีศักยภาพแม้ว่าจะไม่ทำให้เกิดข้อผิดพลาดในเวลารวบรวม

ในทำนองเดียวกัน Java:

public final class Bar {
}

public class Error extends Bar {
}

กลายเป็น C ++ 11:

class Bar final {
};

class Error : public Bar {
};

(ก่อนหน้านี้คอนprivateสตรัคเตอร์อาจใกล้เคียงที่สุดที่คุณจะได้รับใน C ++)

น่าสนใจเพื่อรักษาความเข้ากันได้ย้อนหลังกับรหัส pre-C ++ 11 final ไม่ใช่คำหลักตามปกติ (นำตัวอย่าง C ++ 98 ที่น่าสนใจและถูกกฎหมายstruct final;มาดูว่าทำไมการทำให้คำหลักใช้รหัสผิดพลาด)


3
คุณควรทำให้วิธีการเหล่านั้นเสมือนจริง; มิฉะนั้นคุณไม่ได้ทำสิ่งเดียวกันจริงๆ
BlueRaja - Danny Pflughoeft

1
ในตัวอย่างสุดท้ายของคุณสิ่งที่คุณมีถูกกฎหมาย แต่มันก็คุ้มค่าที่final int a; a = 10; a = 11;จะกล่าวถึงว่าไม่ใช่ (นั่นเป็นจุดประสงค์ของการfinalเป็นตัวแปรปรับปรุง) นอกจากนี้สมาชิกสุดท้ายที่เรียนสามารถตั้งค่าได้ในเวลาที่ประกาศหรือครั้งเดียวในตัวสร้าง .
corsiKa

2
โปรดทราบว่า C ++ 0x เพิ่มตัวfinalตกแต่งฟังก์ชันสมาชิกเพื่อจุดประสงค์ที่แน่นอนนี้ VC ++ 2005 2008 และ 2010 ได้นี้ดำเนินการโดยใช้บริบทของคำหลักมากกว่าsealed final
ildjarn

@ildjarn - มันน่าสนใจที่จะรู้และอีก C + 0x เปลี่ยนแปลงค่อนข้างเล็กที่ฉันไม่รู้ ฉันอาจจะเพิ่มความคิดเห็นเล็ก ๆ ในข้อความที่ระบุว่าสิ่งนี้กำลังเปลี่ยนแปลงด้วย C ++ 0x
เฟล็กโซ

1
เห็นได้ชัดว่าผู้คนยังคงทำ s / const / final / g ในโค้ดเบสที่มีตัว ปรับโครงสร้างเป็นผลลัพธ์!
เฟล็กโซ

30

ใน Java คำหลักสุดท้ายสามารถใช้สำหรับสี่สิ่ง:

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

สิ่งหนึ่งที่สำคัญคือ: ตัวแปรสมาชิก Java สุดท้ายจะต้องตั้งค่าครั้งเดียว! ตัวอย่างเช่นใน Constructor, การประกาศฟิลด์หรือ Intializer (แต่คุณไม่สามารถตั้งค่าตัวแปรสมาชิกสุดท้ายในวิธีการ)

ผลที่ตามมาอีกประการหนึ่งของการทำให้ตัวแปรสมาชิกสุดท้ายเกี่ยวข้องกับโมเดลหน่วยความจำซึ่งมีความสำคัญหากคุณทำงานในสภาพแวดล้อมแบบเธรด


คุณหมายถึงอะไรโดยพูดว่า 'รูปแบบหน่วยความจำ'? ฉันไม่เข้าใจ
Tony

1
@Tony: ข้อกำหนดภาษา Java, บทที่ 17.4 รุ่นของหน่วยความจำ - docs.oracle.com/javase/specs/jls/se8/html/index.html - googles ยอดฮิต
Ralph

27

constวัตถุเท่านั้นที่สามารถเรียกconstวิธีการและโดยทั่วไปถือว่าไม่เปลี่ยนรูป

const Person* person = myself;
person = otherPerson; //Valid... unless we declared it const Person* const!
person->setAge(20); //Invalid, assuming setAge isn't a const method (it shouldn't be)

finalวัตถุไม่สามารถตั้งค่าไปยังวัตถุใหม่ แต่มันไม่ได้เปลี่ยนรูป - ไม่มีอะไรหยุดคนจากการเรียกใด ๆsetวิธี

final Person person = myself;
person = otherPerson; //Invalid
person.setAge(20); //Valid!

Java ไม่มีวิธีในการประกาศวัตถุที่ไม่เปลี่ยนรูป คุณต้องออกแบบชั้นเรียนให้เหมือนตัวเองที่ไม่เปลี่ยนรูป

เมื่อตัวแปรเป็นชนิดดั้งเดิมfinal/ constทำงานเหมือนกัน

const int a = 10; //C++
final int a = 10; //Java
a = 11; //Invalid in both languages

3
นี่เป็นคำตอบที่ยอดเยี่ยมเช่นกัน (เช่นเดียวกับคนอื่น ๆ ที่นี่) น่าเสียดายที่ฉันยอมรับได้เพียงคำตอบเดียวเท่านั้น :)
WinWin

1
คำตอบที่สมบูรณ์แบบ!
ADJ

13

Java ขั้นสุดท้ายเทียบเท่ากับ C ++ const ในประเภทค่าดั้งเดิม

ด้วยประเภทการอ้างอิง Java คำหลักสุดท้ายจะเทียบเท่ากับตัวชี้ const ... เช่น

//java
final int finalInt = 5;
final MyObject finalReference = new MyObject();

//C++
const int constInt = 5;
MyObject * const constPointer = new MyObject();

"คำหลักสุดท้ายเทียบเท่ากับตัวชี้ const" ดีกล่าว
ADJ

8

คุณมีคำตอบที่ดีอยู่แล้วที่นี่ แต่จุดหนึ่งที่ดูเหมือนว่าควรจะเพิ่ม: constใน C ++ มักใช้เพื่อป้องกันส่วนอื่น ๆ ของโปรแกรมที่เปลี่ยนสถานะของวัตถุ ดังที่ได้อธิบายไว้finalใน java ไม่สามารถทำเช่นนี้ได้ (ยกเว้นสำหรับ primitives) - เพียงแค่ป้องกันการอ้างอิงจากการเปลี่ยนเป็นวัตถุอื่น แต่ถ้าคุณใช้ a Collectionคุณสามารถป้องกันการเปลี่ยนแปลงวัตถุของคุณโดยใช้วิธีการคงที่

 Collection.unmodifiableCollection( myCollection ) 

สิ่งนี้ส่งคืนการCollectionอ้างอิงที่ให้การเข้าถึงองค์ประกอบอ่าน แต่จะมีข้อผิดพลาดถ้าพยายามแก้ไขทำให้มันเหมือนกับconstC ++


8

Java ใช้finalงานได้กับชนิดและการอ้างอิงดั้งเดิมเท่านั้นไม่ทำงานกับอินสแตนซ์ของวัตถุที่ตัวคำสั่ง const ทำงานกับสิ่งใด

เปรียบเทียบconst list<int> melist;กับfinal List<Integer> melist;รายการแรกทำให้ไม่สามารถแก้ไขรายการได้ในขณะที่รายการหลังหยุดคุณไม่ให้กำหนดรายการใหม่melistเท่านั้น


3

นอกเหนือจากการมีคุณสมบัติมัลติเธรดที่แน่นอนและละเอียดอ่อนแล้วตัวแปรที่ประกาศfinalไม่จำเป็นต้องเริ่มต้นในการประกาศ!

เช่นนี้ถูกต้องใน Java:

// declare the variable
final int foo;

{
    // do something...

    // and then initialize the variable
    foo = ...;
}

นี้จะไม่ถูกต้องถ้าเขียนด้วยภาษา C ++ const's


2

ตามวิกิพีเดีย :

  • ใน C ++ ฟิลด์ const ไม่ได้ป้องกันเพียงการกำหนดใหม่ แต่มีข้อ จำกัด เพิ่มเติมที่วิธีการ const เท่านั้นที่สามารถเรียกใช้ได้และจะสามารถส่งผ่านเป็นอาร์กิวเมนต์อาร์กิวเมนต์ของวิธีอื่นเท่านั้น
  • คลาสภายในที่ไม่คงที่สามารถเข้าถึงฟิลด์ใด ๆ ของคลาสที่ปิดล้อมได้อย่างอิสระหรือไม่ก็ได้

1
คำว่า 'กำหนดใหม่' ไม่ปรากฏในเวอร์ชันปัจจุบันของหน้านั้นและไม่มีอะไรที่คล้ายกับจุดที่สองของคุณซึ่งไม่ถูกต้องหรือไม่เกี่ยวข้องขึ้นอยู่กับความหมายของ 'การเข้าถึง' 'Non-static Inner' เป็นการสนทนาสองครั้ง Wikipedia ไม่ได้อ้างอิงเชิงบรรทัดฐานสำหรับ C ++ หรือ Java
มาร์ควิสแห่ง Lorne

2

ฉันเดาว่ามันพูดว่า "คร่าว ๆ " เพราะความหมายของconstใน C ++ นั้นซับซ้อนขึ้นเมื่อคุณพูดถึงพอยน์เตอร์นั่นคือพอยน์เตอร์คงที่และพอยน์เตอร์ไปยังวัตถุคงที่ เนื่องจากไม่มีพอยน์เตอร์ "ชัดเจน" ใน Java finalจึงไม่มีปัญหาเหล่านี้


1

ให้ฉันอธิบายสิ่งที่ฉันเข้าใจด้วยตัวอย่างของคำสั่ง switch / case

ค่าในแต่ละคำสั่ง case ต้องเป็นค่าคงที่เวลาคอมไพล์ของชนิดข้อมูลเดียวกันกับค่าสวิตช์

ประกาศบางอย่างเช่นด้านล่าง (ในวิธีการของคุณเป็นกรณีท้องถิ่นหรือในชั้นเรียนของคุณเป็นตัวแปรคงที่ (เพิ่มแบบคงที่แล้ว) หรือตัวแปรอินสแตนซ์

final String color1 = "Red";

และ

static final String color2 = "Green";

switch (myColor) { // myColor is of data type String
    case color1:
    //do something here with Red
    break;
    case color2:
    //do something with Green
    break;
}

รหัสนี้จะไม่รวบรวมถ้าcolor1เป็นตัวแปร class / instance และไม่ใช่ตัวแปรในตัวเครื่อง สิ่งนี้จะคอมไพล์หากcolor1ถูกกำหนดเป็นสแตติกสุดท้าย (จากนั้นจะกลายเป็นตัวแปรสแตติกสุดท้าย)

เมื่อมันไม่ได้รวบรวมคุณจะได้รับข้อผิดพลาดดังต่อไปนี้

error: constant string expression required

-7

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

คำหลัก "final" หมายถึงตัวแปรของคุณถูกบันทึกใน RAM ที่เขียนได้ แต่คุณสังเกตเห็นว่าคอมไพเลอร์ว่าตัวแปรของคุณเปลี่ยนแปลงเพียงครั้งเดียวเท่านั้น

//in java language you can use:
static final int i =10;
i =11; //error is showed here by compiler

//the same in C++ the same as follows
int i =10;
const int &iFinal = i;

iFinal = 11; //error is showed here by compiler the same as above

ฉันคิดว่า "const" ไม่ดีต่อประสิทธิภาพดังนั้น Java จึงไม่ได้ใช้

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