ภายในและเกี่ยวกับโค้ดที่สร้างขึ้นมีความแตกต่างระหว่าง:
MyClass::MyClass(): _capacity(15), _data(NULL), _len(0)
{
}
และ
MyClass::MyClass()
{
_capacity=15;
_data=NULL;
_len=0
}
ขอบคุณ ...
ภายในและเกี่ยวกับโค้ดที่สร้างขึ้นมีความแตกต่างระหว่าง:
MyClass::MyClass(): _capacity(15), _data(NULL), _len(0)
{
}
และ
MyClass::MyClass()
{
_capacity=15;
_data=NULL;
_len=0
}
ขอบคุณ ...
คำตอบ:
สมมติว่าค่าเหล่านั้นเป็นประเภทดั้งเดิมดังนั้นไม่ใช่ไม่มีความแตกต่าง รายการเริ่มต้นจะสร้างความแตกต่างเมื่อคุณมีอ็อบเจ็กต์เป็นสมาชิกเท่านั้นเนื่องจากแทนที่จะใช้การกำหนดค่าเริ่มต้นตามด้วยการกำหนดรายการเริ่มต้นจะช่วยให้คุณกำหนดค่าเริ่มต้นของออบเจ็กต์เป็นค่าสุดท้ายได้ สิ่งนี้สามารถเร็วขึ้นอย่างเห็นได้ชัด
คุณต้องใช้รายการเริ่มต้นเพื่อเริ่มต้นสมาชิกค่าคงที่การอ้างอิงและคลาสพื้นฐาน
เมื่อคุณต้องการเริ่มต้นสมาชิกค่าคงที่การอ้างอิงและส่งผ่านพารามิเตอร์ไปยังตัวสร้างคลาสพื้นฐานตามที่กล่าวไว้ในความคิดเห็นคุณต้องใช้รายการเริ่มต้น
struct aa
{
int i;
const int ci; // constant member
aa() : i(0) {} // will fail, constant member not initialized
};
struct aa
{
int i;
const int ci;
aa() : i(0) { ci = 3;} // will fail, ci is constant
};
struct aa
{
int i;
const int ci;
aa() : i(0), ci(3) {} // works
};
ตัวอย่างคลาส / โครงสร้าง (ไม่ครบถ้วนสมบูรณ์) มีการอ้างอิง:
struct bb {};
struct aa
{
bb& rb;
aa(bb& b ) : rb(b) {}
};
// usage:
bb b;
aa a(b);
และตัวอย่างการเตรียมใช้งานคลาสฐานที่ต้องการพารามิเตอร์ (เช่นไม่มีตัวสร้างเริ่มต้น):
struct bb {};
struct dd
{
char c;
dd(char x) : c(x) {}
};
struct aa : dd
{
bb& rb;
aa(bb& b ) : dd('a'), rb(b) {}
};
_capacity
, _data
และ_len
มีชนิดชั้นโดยไม่ต้องมีการก่อสร้างเริ่มต้นที่สามารถเข้าถึงได้?
const
สมาชิกในเนื้อหาของตัวสร้างได้คุณต้องใช้รายการการเริ่มต้น - const
สมาชิกที่ไม่ใช่สามารถเริ่มต้นได้ในรายการเริ่มต้นหรือในเนื้อหาของตัวสร้าง
ใช่. ในกรณีแรกที่คุณสามารถประกาศ_capacity
, _data
และ_len
เป็นค่าคงที่:
class MyClass
{
private:
const int _capacity;
const void *_data;
const int _len;
// ...
};
สิ่งนี้มีความสำคัญหากคุณต้องการตรวจสอบความเป็นไปได้const
ของตัวแปรอินสแตนซ์เหล่านี้ในขณะที่คำนวณค่าที่รันไทม์ตัวอย่างเช่น:
MyClass::MyClass() :
_capacity(someMethod()),
_data(someOtherMethod()),
_len(yetAnotherMethod())
{
}
const
อินสแตนซ์ต้องถูกเตรียมใช้งานในรายการ initializer หรือประเภทพื้นฐานต้องจัดเตรียมคอนสตรัคเตอร์แบบไม่มีพารามิเตอร์สาธารณะ (ซึ่งประเภทดั้งเดิมทำ)
ฉันคิดว่าลิงค์นี้http://www.cplusplus.com/forum/articles/17820/ให้คำอธิบายที่ยอดเยี่ยม - โดยเฉพาะสำหรับผู้ที่เพิ่งเริ่มใช้ C ++
สาเหตุที่รายการ intialiser มีประสิทธิภาพมากกว่าคือภายในตัวสร้างจะมีการกำหนดเฉพาะการกำหนดเท่านั้นไม่ใช่การเริ่มต้น ดังนั้นหากคุณกำลังจัดการกับประเภทที่ไม่ใช่ในตัวตัวสร้างเริ่มต้นสำหรับวัตถุนั้นจึงถูกเรียกก่อนที่จะป้อนเนื้อหาของตัวสร้าง ภายในตัวสร้างคุณกำลังกำหนดค่าให้กับวัตถุนั้น
ผลนี้เป็นการเรียกไปยังตัวสร้างเริ่มต้นตามด้วยการเรียกไปยังตัวดำเนินการกำหนดสำเนา รายการเริ่มต้นช่วยให้คุณสามารถเรียกตัวสร้างการคัดลอกได้โดยตรงและบางครั้งอาจเร็วกว่ามาก (โปรดจำไว้ว่ารายการตัวเริ่มต้นอยู่ก่อนเนื้อหาของตัวสร้าง)
ฉันจะเพิ่มว่าถ้าคุณมีสมาชิกประเภทคลาสที่ไม่มีตัวสร้างเริ่มต้นการเริ่มต้นเป็นวิธีเดียวในการสร้างคลาสของคุณ
ความแตกต่างอย่างมากคือการมอบหมายสามารถเริ่มต้นสมาชิกของคลาสแม่ได้ initializer ใช้งานได้กับสมาชิกที่ประกาศในขอบเขตคลาสปัจจุบันเท่านั้น
ขึ้นอยู่กับประเภทที่เกี่ยวข้อง ความแตกต่างมีความคล้ายคลึงกันระหว่าง
std::string a;
a = "hai";
และ
std::string a("hai");
โดยที่รูปแบบที่สองคือรายการเริ่มต้นนั่นคือจะสร้างความแตกต่างหากประเภทต้องการอาร์กิวเมนต์ตัวสร้างหรือมีประสิทธิภาพมากกว่าด้วยอาร์กิวเมนต์ตัวสร้าง
ความแตกต่างที่แท้จริงคือวิธีที่คอมไพเลอร์ gcc สร้างรหัสเครื่องและวางหน่วยความจำ อธิบาย:
มีวิธีอื่น ๆ ในการจัดการกับสมาชิกประเภท const อย่างแน่นอน แต่เพื่อให้ชีวิตของพวกเขาง่ายขึ้นนักเขียนคอมไพเลอร์ gcc จึงตัดสินใจตั้งกฎเกณฑ์บางอย่าง
มีเพียงวิธีเดียวในการเตรียมใช้งานอินสแตนซ์คลาสพื้นฐานและตัวแปรสมาชิกที่ไม่คงที่และนั่นคือการใช้รายการตัวเริ่มต้น
หากคุณไม่ได้ระบุตัวแปรสมาชิกฐานหรือไม่คงที่ในรายการตัวเริ่มต้นของตัวสร้างของคุณสมาชิกหรือฐานนั้นจะถูกกำหนดค่าเริ่มต้นโดยปริยาย (ถ้าสมาชิก / ฐานเป็นประเภทคลาสที่ไม่ใช่ POD หรืออาร์เรย์ของคลาสที่ไม่ใช่ POD ประเภท) หรือปล่อยไว้โดยไม่ได้เริ่มต้นเป็นอย่างอื่น
เมื่อเข้าสู่เนื้อหาตัวสร้างแล้วฐานหรือสมาชิกทั้งหมดจะถูกกำหนดค่าเริ่มต้นหรือปล่อยทิ้งไว้โดยไม่ได้กำหนดค่าเริ่มต้น (กล่าวคือจะมีค่าที่ไม่แน่นอน) ไม่มีโอกาสในตัวสร้างที่จะมีอิทธิพลต่อวิธีการเริ่มต้นของพวกเขา
คุณอาจกำหนดค่าใหม่ให้กับสมาชิกในเนื้อหาตัวสร้างได้ แต่ไม่สามารถกำหนดให้กับconst
สมาชิกหรือสมาชิกของประเภทชั้นเรียนที่ไม่สามารถกำหนดได้และไม่สามารถเชื่อมโยงการอ้างอิงซ้ำได้
สำหรับชนิดที่สร้างขึ้นและประเภทที่ผู้ใช้กำหนดเองการกำหนดในเนื้อหาตัวสร้างอาจมีผลเหมือนกับการเริ่มต้นด้วยค่าเดียวกันในรายการตัวเริ่มต้น
หากคุณล้มเหลวในการตั้งชื่อสมาชิกหรือฐานในรายการตัวเริ่มต้นและเอนทิตีนั้นเป็นข้อมูลอ้างอิงมีประเภทคลาสที่ไม่มีตัวสร้างเริ่มต้นที่ผู้ใช้ประกาศซึ่งสามารถเข้าถึงได้const
มีคุณสมบัติและมีประเภท POD หรือเป็นประเภทคลาส POD หรืออาร์เรย์ของประเภทคลาส POD มีconst
สมาชิกที่มีคุณสมบัติเหมาะสม (โดยตรงหรือโดยอ้อม) แสดงว่าโปรแกรมมีรูปแบบไม่ถูกต้อง
หากคุณเขียนรายการเริ่มต้นคุณจะทำทั้งหมดในขั้นตอนเดียว หากคุณไม่เขียนรายการตัวเริ่มต้นคุณจะทำ 2 ขั้นตอนคือขั้นตอนหนึ่งสำหรับการประกาศและอีกขั้นสำหรับการกำหนดค่า
มีความแตกต่างระหว่างรายการเริ่มต้นและคำสั่งเริ่มต้นในตัวสร้าง ลองพิจารณาโค้ดด้านล่าง:
#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <numeric>
class MyBase {
public:
MyBase() {
std::cout << __FUNCTION__ << std::endl;
}
};
class MyClass : public MyBase {
public:
MyClass::MyClass() : _capacity( 15 ), _data( NULL ), _len( 0 ) {
std::cout << __FUNCTION__ << std::endl;
}
private:
int _capacity;
int* _data;
int _len;
};
class MyClass2 : public MyBase {
public:
MyClass2::MyClass2() {
std::cout << __FUNCTION__ << std::endl;
_capacity = 15;
_data = NULL;
_len = 0;
}
private:
int _capacity;
int* _data;
int _len;
};
int main() {
MyClass c;
MyClass2 d;
return 0;
}
เมื่อใช้ MyClass สมาชิกทั้งหมดจะถูกเตรียมใช้งานก่อนคำสั่งแรกในตัวสร้างที่ดำเนินการ
แต่เมื่อใช้ MyClass2 สมาชิกทั้งหมดจะไม่ถูกเตรียมใช้งานเมื่อคำสั่งแรกในตัวสร้างดำเนินการ
ในภายหลังอาจมีปัญหาการถดถอยเมื่อมีคนเพิ่มรหัสในตัวสร้างก่อนที่สมาชิกบางคนจะเริ่มต้น
นี่คือประเด็นที่ฉันไม่เห็นคนอื่นอ้างถึง:
class temp{
public:
temp(int var);
};
คลาส temp ไม่มี ctor เริ่มต้น เมื่อนำไปใช้ในคลาสอื่นดังนี้
class mainClass{
public:
mainClass(){}
private:
int a;
temp obj;
};
โค้ดจะไม่คอมไพล์ทำให้คอมไพลเลอร์ไม่ทราบวิธีการเริ่มต้นobj
เนื่องจากมีเพียง ctor ที่ชัดเจนซึ่งได้รับค่า int ดังนั้นเราจึงต้องเปลี่ยน ctor ดังนี้:
mainClass(int sth):obj(sth){}
ดังนั้นจึงไม่ใช่แค่เรื่อง const และการอ้างอิงเท่านั้น!