เพื่อชี้แจงคำถามฉันต้องการจัดหมวดหมู่การใช้คำหลัก 'คงที่' ในรูปแบบที่แตกต่างกันสามแบบ:
(A) ตัวแปร
(B) ฟังก์ชั่น
(ค). ตัวแปรสมาชิก / ฟังก์ชั่นของการเรียน
คำอธิบายด้านล่างสำหรับแต่ละหัวข้อย่อย:
(A) คำหลัก 'คงที่' สำหรับตัวแปร
อันนี้อาจจะยุ่งยากเล็กน้อย แต่ถ้าอธิบายและเข้าใจอย่างถูกต้องมันค่อนข้างตรงไปตรงมา
เพื่ออธิบายสิ่งนี้สิ่งแรกคือมีประโยชน์จริง ๆ ที่จะรู้เกี่ยวกับขอบเขตระยะเวลาและการเชื่อมโยงของตัวแปรโดยที่สิ่งต่าง ๆ มักจะยากที่จะมองผ่านแนวคิดที่มืดมนของคำหลักที่เก่าแก่
1. ขอบเขต : กำหนดตำแหน่งที่อยู่ในไฟล์ตัวแปรสามารถเข้าถึงได้ มันอาจจะเป็นสองประเภท: (i) ท้องถิ่นหรือปิดกั้นขอบเขต (ii) ขอบเขตทั่วโลก
2. ระยะเวลา : กำหนดว่าเมื่อใดที่ตัวแปรถูกสร้างและทำลาย อีกครั้งเป็นสองประเภท: (i) Automatic Storage Duration (สำหรับตัวแปรที่มีขอบเขต Local หรือ Block) (ii) Static Storage Duration (สำหรับตัวแปรที่มีขอบเขตทั่วโลกหรือตัวแปรท้องถิ่น (ในฟังก์ชั่นหรือ a ในบล็อกรหัส) พร้อมตัวระบุแบบคงที่)
3. การเชื่อมโยง : กำหนดว่าตัวแปรสามารถเข้าถึงได้ (หรือเชื่อมโยง) ในไฟล์อื่น อีกครั้ง (และโชคดี) เป็นสองประเภท: (i) การเชื่อมโยงภายใน
(สำหรับตัวแปรที่มีขอบเขตการบล็อกและขอบเขต / ขอบเขตไฟล์ทั่วโลก / ขอบเขตเนมสเปซส่วนกลาง) (ii) การเชื่อมโยงภายนอก (สำหรับตัวแปรที่มีเฉพาะขอบเขตสากล / ขอบเขตไฟล์ / ขอบเขตเนมสเปซส่วนกลาง)
ลองอ้างอิงตัวอย่างด้านล่างเพื่อทำความเข้าใจกับตัวแปรโกลบอลและโลคัลที่ดีขึ้น (ไม่มีตัวแปรโลคัลที่มีระยะเวลาเก็บแบบคงที่):
//main file
#include <iostream>
int global_var1; //has global scope
const global_var2(1.618); //has global scope
int main()
{
//these variables are local to the block main.
//they have automatic duration, i.e, they are created when the main() is
// executed and destroyed, when main goes out of scope
int local_var1(23);
const double local_var2(3.14);
{
/* this is yet another block, all variables declared within this block are
have local scope limited within this block. */
// all variables declared within this block too have automatic duration, i.e,
/*they are created at the point of definition within this block,
and destroyed as soon as this block ends */
char block_char1;
int local_var1(32) //NOTE: this has been re-declared within the block,
//it shadows the local_var1 declared outside
std::cout << local_var1 <<"\n"; //prints 32
}//end of block
//local_var1 declared inside goes out of scope
std::cout << local_var1 << "\n"; //prints 23
global_var1 = 29; //global_var1 has been declared outside main (global scope)
std::cout << global_var1 << "\n"; //prints 29
std::cout << global_var2 << "\n"; //prints 1.618
return 0;
} //local_var1, local_var2 go out of scope as main ends
//global_var1, global_var2 go out of scope as the program terminates
//(in this case program ends with end of main, so both local and global
//variable go out of scope together
ตอนนี้เป็นแนวคิดของการเชื่อมโยง เมื่อตัวแปรโกลบอลที่กำหนดไว้ในไฟล์เดียวมีวัตถุประสงค์เพื่อใช้ในไฟล์อื่นการเชื่อมโยงของตัวแปรจะมีบทบาทสำคัญ
การเชื่อมโยงของตัวแปรทั่วโลกมีการระบุโดยคำหลัก: (i) คงที่และ (ii) ภายนอก
(ตอนนี้คุณจะได้คำอธิบาย)
คำหลักคงที่สามารถนำไปใช้กับตัวแปรที่มีขอบเขตท้องถิ่นและทั่วโลกและในทั้งสองกรณีพวกเขาหมายถึงสิ่งที่แตกต่างกัน ฉันจะอธิบายการใช้คำหลัก 'คงที่' ในตัวแปรที่มีขอบเขตทั่วโลก (ซึ่งฉันจะอธิบายการใช้คำหลัก 'ภายนอก' ด้วย) และหลังจากนั้นสำหรับคำหลักที่มีขอบเขตในท้องถิ่น
1. คำหลักคงที่สำหรับตัวแปรที่มีขอบเขตทั่วโลก
ตัวแปรทั่วโลกมีระยะเวลาคงที่ซึ่งหมายความว่าพวกเขาจะไม่ออกนอกขอบเขตเมื่อบล็อกรหัสเฉพาะ (เช่น main ()) ที่มีการใช้งานสิ้นสุดลง ขึ้นอยู่กับการเชื่อมโยงพวกเขาสามารถเข้าถึงได้เฉพาะภายในไฟล์เดียวกับที่พวกเขาจะประกาศ (สำหรับตัวแปรทั่วโลกคงที่) หรือนอกไฟล์แม้นอกไฟล์ที่พวกเขาจะประกาศ (ประเภทตัวแปรทั่วโลกภายนอก)
ในกรณีของตัวแปรโกลบอลที่มีตัวระบุ extern และหากตัวแปรนี้ถูกเข้าถึงภายนอกไฟล์ที่ถูกกำหนดค่าเริ่มต้นจะต้องมีการประกาศไปข้างหน้าในไฟล์ที่มีการใช้งานเช่นเดียวกับฟังก์ชั่นที่ต้องส่งต่อ ประกาศถ้าคำจำกัดความของมันอยู่ในไฟล์ที่แตกต่างจากที่มันถูกใช้
ในทางตรงกันข้ามหากตัวแปรโกลบอลมีคำหลักคงที่จะไม่สามารถใช้ไฟล์นั้นนอกไฟล์ที่ได้รับการประกาศ
(ดูตัวอย่างด้านล่างเพื่อความกระจ่าง)
เช่น:
//main2.cpp
static int global_var3 = 23; /*static global variable, cannot be
accessed in anyother file */
extern double global_var4 = 71; /*can be accessed outside this file linked to main2.cpp */
int main() { return 0; }
main3.cpp
//main3.cpp
#include <iostream>
int main()
{
extern int gloabl_var4; /*this variable refers to the gloabal_var4
defined in the main2.cpp file */
std::cout << global_var4 << "\n"; //prints 71;
return 0;
}
ตอนนี้ตัวแปรใด ๆ ใน c ++ สามารถเป็น const หรือ non-const และสำหรับแต่ละ 'const-ness' เราจะได้รับสองกรณีของการเชื่อมโยง c ++ เริ่มต้นในกรณีที่ไม่มีการระบุ:
(i) หากตัวแปรโกลบอลไม่ใช่แบบ const การเชื่อมโยงของมันจะเป็นค่าเริ่มต้นเช่นตัวแปรแบบโกลบอลที่ไม่ใช่ const สามารถเข้าถึงได้ในไฟล์. cpp อื่นโดยการประกาศไปข้างหน้าโดยใช้คำสำคัญ extern (ในคำอื่น ๆ ไม่ใช่ const global ตัวแปรมีการเชื่อมโยงภายนอก (ที่มีระยะเวลาคงที่แน่นอน)) การใช้คำหลัก extern ในไฟล์ต้นฉบับที่มีการกำหนดนั้นซ้ำซ้อน ในกรณีนี้จะทำให้ไม่ใช่ const ไม่สามารถเข้าถึงตัวแปรทั่วโลกไปยังแฟ้มภายนอกใช้ระบุว่า 'คงที่' ก่อนที่ประเภทของตัวแปร
(ii) ถ้าตัวแปรโกลบอลเป็น const การเชื่อมโยงของมันจะเป็นค่าคงที่โดยค่าเริ่มต้นเช่นตัวแปรโกลบอล const ไม่สามารถเข้าถึงได้ในไฟล์อื่นนอกเหนือจากที่มันถูกกำหนดไว้ (กล่าวอีกนัยหนึ่งว่าตัวแปรโกลบอลของ const มีการเชื่อมโยงภายใน แน่นอน)). การใช้คำหลักแบบสแตติกเพื่อป้องกันไม่ให้ตัวแปรโกลบอล const ถูกเข้าถึงในไฟล์อื่นนั้นซ้ำซ้อน ในที่นี้เพื่อให้ตัวแปรโกลบอล const มีการเชื่อมโยงภายนอกให้ใช้ตัวระบุ 'extern' ก่อนชนิดของตัวแปร
นี่คือบทสรุปสำหรับตัวแปรขอบเขตทั่วโลกที่มีการเชื่อมโยงที่หลากหลาย
//globalVariables1.cpp
// defining uninitialized vairbles
int globalVar1; // uninitialized global variable with external linkage
static int globalVar2; // uninitialized global variable with internal linkage
const int globalVar3; // error, since const variables must be initialized upon declaration
const int globalVar4 = 23; //correct, but with static linkage (cannot be accessed outside the file where it has been declared*/
extern const double globalVar5 = 1.57; //this const variable ca be accessed outside the file where it has been declared
ต่อไปเราจะตรวจสอบว่าตัวแปรทั่วโลกทำงานอย่างไรเมื่อเข้าถึงในไฟล์อื่น
//using_globalVariables1.cpp (eg for the usage of global variables above)
// Forward declaration via extern keyword:
extern int globalVar1; // correct since globalVar1 is not a const or static
extern int globalVar2; //incorrect since globalVar2 has internal linkage
extern const int globalVar4; /* incorrect since globalVar4 has no extern
specifier, limited to internal linkage by
default (static specifier for const variables) */
extern const double globalVar5; /*correct since in the previous file, it
has extern specifier, no need to initialize the
const variable here, since it has already been
legitimately defined perviously */
2. คำหลักคงที่สำหรับตัวแปรที่มีขอบเขตในเครื่อง
อัปเดต (สิงหาคม 2019) กับคำหลักคงที่สำหรับตัวแปรในขอบเขตท้องถิ่น
นอกจากนี้ยังสามารถแบ่งย่อยในสองประเภท:
(i) คำหลักคงที่สำหรับตัวแปรภายในบล็อกฟังก์ชั่นและ(ii) คำหลักคงที่สำหรับตัวแปรภายในบล็อกท้องถิ่นที่ไม่มีชื่อ
(i) คำหลักคงที่สำหรับตัวแปรภายในบล็อกฟังก์ชั่น
ก่อนหน้านี้ฉันพูดถึงว่าตัวแปรที่มีขอบเขตภายในมีระยะเวลาอัตโนมัตินั่นคือมันจะมีอยู่เมื่อบล็อกถูกป้อน (ไม่ว่าจะเป็นบล็อกปกติไม่ว่าจะเป็นบล็อกการทำงาน) และหยุดอยู่เมื่อบล็อกจบเรื่องสั้นสั้นยาวตัวแปร ที่มีขอบเขตในเครื่องจะมีช่วงเวลาอัตโนมัติและตัวแปรระยะเวลาอัตโนมัติ (และวัตถุ) ไม่มีการเชื่อมโยงหมายความว่าจะไม่สามารถมองเห็นได้นอกบล็อกรหัส
หากตัวระบุแบบคงที่ถูกนำไปใช้กับตัวแปรท้องถิ่นภายในบล็อกฟังก์ชั่นมันจะเปลี่ยนระยะเวลาของตัวแปรจากอัตโนมัติเป็นแบบคงที่และเวลาชีวิตของมันคือระยะเวลาทั้งหมดของโปรแกรมซึ่งหมายความว่ามันมีตำแหน่งหน่วยความจำคงที่และค่าเริ่มต้นเท่านั้น หนึ่งครั้งก่อนที่โปรแกรมจะเริ่มทำงานดังกล่าวในการอ้างอิง cpp (การกำหนดค่าเริ่มต้นไม่ควรสับสนกับการกำหนด)
ลองมาดูตัวอย่าง
//localVarDemo1.cpp
int localNextID()
{
int tempID = 1; //tempID created here
return tempID++; //copy of tempID returned and tempID incremented to 2
} //tempID destroyed here, hence value of tempID lost
int newNextID()
{
static int newID = 0;//newID has static duration, with internal linkage
return newID++; //copy of newID returned and newID incremented by 1
} //newID doesn't get destroyed here :-)
int main()
{
int employeeID1 = localNextID(); //employeeID1 = 1
int employeeID2 = localNextID(); // employeeID2 = 1 again (not desired)
int employeeID3 = newNextID(); //employeeID3 = 0;
int employeeID4 = newNextID(); //employeeID4 = 1;
int employeeID5 = newNextID(); //employeeID5 = 2;
return 0;
}
เมื่อมองจากเกณฑ์ข้างต้นสำหรับตัวแปรสแตติกท้องถิ่นและตัวแปรสแตติกทั่วโลกเราอาจถูกล่อลวงให้ถามว่าอะไรคือความแตกต่างระหว่างพวกเขา ในขณะที่ตัวแปรทั่วโลกสามารถเข้าถึงได้ที่จุดใด ๆ ภายในรหัส (ในเช่นเดียวกับหน่วยการแปลที่แตกต่างกันขึ้นอยู่กับconst -ness และextern -ness) ตัวแปรคงที่กำหนดภายในบล็อกฟังก์ชั่นไม่สามารถเข้าถึงได้โดยตรง ต้องส่งคืนตัวแปรโดยค่าฟังก์ชันหรือการอ้างอิง ให้แสดงตัวอย่างนี้โดย:
//localVarDemo2.cpp
//static storage duration with global scope
//note this variable can be accessed from outside the file
//in a different compilation unit by using `extern` specifier
//which might not be desirable for certain use case.
static int globalId = 0;
int newNextID()
{
static int newID = 0;//newID has static duration, with internal linkage
return newID++; //copy of newID returned and newID incremented by 1
} //newID doesn't get destroyed here
int main()
{
//since globalId is accessible we use it directly
const int globalEmployee1Id = globalId++; //globalEmployeeId1 = 0;
const int globalEmployee2Id = globalId++; //globalEmployeeId1 = 1;
//const int employeeID1 = newID++; //this will lead to compilation error since newID++ is not accessible direcly.
int employeeID2 = newNextID(); //employeeID3 = 0;
int employeeID2 = newNextID(); //employeeID3 = 1;
return 0;
}
คำอธิบายเพิ่มเติมเกี่ยวกับตัวเลือกของตัวแปรโลคัลโกลบอลและสแตติกแบบคงที่สามารถพบได้บนเธรดสแต็ก
(ii) คำหลักคงที่สำหรับตัวแปรภายในบล็อกโลคัลที่ไม่มีชื่อ
ตัวแปรสแตติกภายในบล็อกโลคัล (ไม่ใช่บล็อกฟังก์ชัน) ไม่สามารถเข้าถึงได้นอกบล็อกเมื่อบล็อกโลคัลอยู่นอกขอบเขต ไม่มีข้อควรปฏิบัติสำหรับกฎนี้
//localVarDemo3.cpp
int main()
{
{
const static int static_local_scoped_variable {99};
}//static_local_scoped_variable goes out of scope
//the line below causes compilation error
//do_something is an arbitrary function
do_something(static_local_scoped_variable);
return 0;
}
C ++ 11 แนะนำคำสำคัญconstexpr
ที่รับประกันการประเมินผลของการแสดงออกในเวลารวบรวมและช่วยให้คอมไพเลอร์เพื่อเพิ่มประสิทธิภาพรหัส ตอนนี้ถ้าค่าของตัวแปร const constexpr
คงอยู่ในขอบเขตที่เป็นที่รู้จักกันที่รวบรวมเวลารหัสมีการเพิ่มประสิทธิภาพในลักษณะที่คล้ายคลึงกับหนึ่งเดียวกับที่ นี่คือตัวอย่างเล็ก ๆ
ฉันขอแนะนำให้ผู้อ่านเพื่อค้นหาความแตกต่างระหว่างconstexpr
และstatic const
สำหรับตัวแปรในเธรด stackoverflowนี้ นี้สรุปคำอธิบายของฉันสำหรับคำหลักคงที่นำไปใช้กับตัวแปร
คำหลัก B. 'คงที่' ใช้สำหรับฟังก์ชั่น
ในแง่ของฟังก์ชั่นคำหลักคงที่มีความหมายตรงไปตรงมา นี่มันหมายถึงการเชื่อมโยงของฟังก์ชั่น
โดยปกติฟังก์ชั่นทั้งหมดที่ประกาศภายในไฟล์ cpp มีการเชื่อมโยงภายนอกโดยค่าเริ่มต้นคือฟังก์ชั่นที่กำหนดไว้ในไฟล์หนึ่งสามารถใช้ในไฟล์ cpp อื่นโดยการประกาศไปข้างหน้า
ใช้คำสำคัญคงที่ก่อนประกาศฟังก์ชั่น จำกัด การเชื่อมโยงไปยังภายในเช่นฟังก์ชั่นคงที่ไม่สามารถใช้ภายในไฟล์นอกคำจำกัดความของมัน
C. Staitc Keyword ใช้สำหรับตัวแปรสมาชิกและฟังก์ชั่นของคลาส
1. คำหลัก 'คงที่' สำหรับตัวแปรสมาชิกของคลาส
ฉันเริ่มต้นโดยตรงจากตัวอย่างที่นี่
#include <iostream>
class DesignNumber
{
private:
static int m_designNum; //design number
int m_iteration; // number of iterations performed for the design
public:
DesignNumber() { } //default constructor
int getItrNum() //get the iteration number of design
{
m_iteration = m_designNum++;
return m_iteration;
}
static int m_anyNumber; //public static variable
};
int DesignNumber::m_designNum = 0; // starting with design id = 0
// note : no need of static keyword here
//causes compiler error if static keyword used
int DesignNumber::m_anyNumber = 99; /* initialization of inclass public
static member */
enter code here
int main()
{
DesignNumber firstDesign, secondDesign, thirdDesign;
std::cout << firstDesign.getItrNum() << "\n"; //prints 0
std::cout << secondDesign.getItrNum() << "\n"; //prints 1
std::cout << thirdDesign.getItrNum() << "\n"; //prints 2
std::cout << DesignNumber::m_anyNumber++ << "\n"; /* no object
associated with m_anyNumber */
std::cout << DesignNumber::m_anyNumber++ << "\n"; //prints 100
std::cout << DesignNumber::m_anyNumber++ << "\n"; //prints 101
return 0;
}
ในตัวอย่างนี้ตัวแปรแบบคงที่ m_designNum จะเก็บค่าไว้และตัวแปรสมาชิกส่วนบุคคลเดียว (เพราะเป็นแบบคงที่) จะถูกแชร์ b / w ตัวแปรทั้งหมดของประเภทวัตถุ DesignNumber
เช่นเดียวกับตัวแปรสมาชิกอื่น ๆ ตัวแปรสมาชิกแบบคงที่ของคลาสไม่เกี่ยวข้องกับคลาสอ็อบเจ็กต์ใด ๆ ซึ่งแสดงให้เห็นโดยการพิมพ์ anyNumber ในฟังก์ชันหลัก
const vs ตัวแปรสมาชิกคงไม่ใช่ const ในชั้นเรียน
(i) ตัวแปรสมาชิกแบบคงที่ที่ไม่ใช่สมาชิกคลาส
ในตัวอย่างก่อนหน้าสมาชิกแบบคงที่ (ทั้งสาธารณะและส่วนตัว) ไม่ใช่ค่าคงที่ มาตรฐาน ISO ห้ามสมาชิกแบบคงที่ที่ไม่ใช่สมาชิกที่จะเริ่มต้นในชั้นเรียน ดังนั้นในตัวอย่างก่อนหน้านี้พวกเขาจะต้อง initalized หลังจากที่คำจำกัดความของชั้นเรียนโดยมีข้อแม้ที่คำหลักคงที่จะต้องละเว้น
(ii) ตัวแปรสมาชิก const-static ของชั้น
นี้ตรงไปตรงมาและไปกับการประชุมของการเริ่มต้นตัวแปรสมาชิก const อื่น ๆ เช่นตัวแปร const สมาชิกคงที่ของชั้นสามารถเริ่มต้น ณ จุดของการประกาศและพวกเขาสามารถเริ่มต้นได้ในตอนท้าย ของการประกาศคลาสด้วยหนึ่ง caveat ที่ const สำคัญต้องถูกเพิ่มไปยังสมาชิกแบบคงที่เมื่อเริ่มต้นหลังจากการกำหนดคลาส
อย่างไรก็ตามฉันขอแนะนำให้เริ่มต้นตัวแปรสมาชิกคงที่ const ณ จุดประกาศ สิ่งนี้ไปกับการประชุม C ++ มาตรฐานและทำให้โค้ดดูสะอาดตา
สำหรับตัวอย่างเพิ่มเติมเกี่ยวกับตัวแปรสมาชิกแบบคงที่ในชั้นเรียนค้นหาลิงก์ต่อไปนี้จาก learncpp.com
http://www.learncpp.com/cpp-tutorial/811-static-member-variables/
2. คีย์เวิร์ด 'static' สำหรับฟังก์ชันสมาชิกของคลาส
เช่นเดียวกับตัวแปรสมาชิกของคลาสสามารถเป็นแบบสแตติกได้ดังนั้นฟังก์ชันสมาชิกของคลาสสามารถทำได้ ฟังก์ชั่นสมาชิกปกติของการเรียนมักจะเกี่ยวข้องกับวัตถุประเภทชั้นเรียน ในทางตรงกันข้ามฟังก์ชั่นสมาชิกคงที่ของชั้นเรียนไม่ได้เกี่ยวข้องกับวัตถุใด ๆ ของชั้นเรียนคือพวกเขาไม่มี * ตัวชี้นี้
ประการที่สองเนื่องจากฟังก์ชั่นสมาชิกคงที่ของชั้นเรียนไม่มี * ตัวชี้นี้พวกเขาสามารถเรียกใช้ชื่อคลาสและผู้ประกอบการแก้ไขขอบเขตในฟังก์ชั่นหลัก (ClassName :: functionName ();)
ฟังก์ชันสมาชิกแบบสแตติกที่สามของคลาสสามารถเข้าถึงตัวแปรสมาชิกแบบคงที่ของคลาสเท่านั้นเนื่องจากตัวแปรสมาชิกแบบไม่คงที่ของคลาสจะต้องเป็นของวัตถุคลาส
สำหรับตัวอย่างเพิ่มเติมเกี่ยวกับฟังก์ชั่นสมาชิกคงที่ในชั้นเรียนค้นหาลิงค์ต่อไปนี้จาก learncpp.com
http://www.learncpp.com/cpp-tutorial/812-static-member-functions/