Câu hỏi Một dấu hai chấm sau một tên hàm dựng C ++ là gì? [bản sao]


Câu hỏi này đã có câu trả lời ở đây:

Toán tử dấu hai chấm (":") làm gì trong hàm tạo này? Nó có tương đương với MyClass(m_classID = -1, m_userdata = 0);?

class MyClass {
public:

    MyClass() : m_classID(-1), m_userdata(0) { 
    }

    int m_classID;
    void *m_userdata;
};

76
2017-08-13 15:22


gốc




Các câu trả lời:


Đây là danh sách khởi tạovà là một phần của việc triển khai của nhà xây dựng.

Chữ ký của hàm tạo là:

MyClass();

Điều này có nghĩa là hàm tạo có thể được gọi không có tham số. Điều này làm cho nó một nhà xây dựng mặc định, tức là, cái sẽ được gọi theo mặc định khi bạn viết MyClass someObject;.

Phần : m_classID(-1), m_userdata(0) được gọi là danh sách khởi tạo. Đó là một cách để khởi tạo một số trường của đối tượng của bạn (tất cả chúng, nếu bạn muốn) với các giá trị của sự lựa chọn của bạn, thay vì để chúng là không xác định.

Sau khi thực thi danh sách khởi tạo, phần thân của hàm tạo (có thể rỗng trong ví dụ của bạn) được thực hiện. Bên trong nó, bạn có thể thực hiện nhiều nhiệm vụ hơn, nhưng một khi bạn đã nhập tất cả các trường đã được khởi tạo - hoặc là ngẫu nhiên, không xác định các giá trị, hoặc cho những cái bạn đã chọn trong danh sách khởi tạo của bạn. Điều này có nghĩa là các bài tập bạn làm trong phần thân của hàm tạo sẽ không được khởi tạo, mà là các thay đổi của các giá trị.


82
2017-08-13 15:26





Nó là một danh sách khởi tạo.

Vào thời điểm bạn nhận được trong cơ thể của các nhà xây dựng, tất cả các lĩnh vực đã được xây dựng; nếu họ có các nhà xây dựng mặc định, những người đó đã được gọi. Bây giờ, nếu bạn chỉ định giá trị cho chúng trong phần thân của hàm tạo, bạn đang gọi toán tử gán bản sao, điều này có nghĩa là giải phóng tài nguyên (ví dụ bộ nhớ) nếu đối tượng có bất kỳ.

Vì vậy, trong trường hợp các kiểu nguyên thủy như int, không có lợi thế so với việc gán chúng trong phần thân của hàm tạo. Trong trường hợp các đối tượng có một hàm tạo, nó là một tối ưu hóa hiệu suất vì nó tránh đi qua hai khởi tạo đối tượng thay vì một.

Một danh sách khởi tạo là cần thiết nếu một trong các trường là một tham chiếu vì một tham chiếu không bao giờ có thể rỗng, thậm chí không trong thời gian ngắn giữa việc xây dựng đối tượng và phần thân của hàm tạo. Lỗi sau đây làm tăng C2758: 'MyClass :: member_': phải được khởi tạo trong danh sách khởi tạo cơ sở / thành viên ban đầu

class MyClass {
public :
    MyClass(std::string& arg) {
        member_ = arg;
    }
    std::string& member_;
};

Cách chính xác duy nhất là:

class MyClass {
public :
    MyClass(std::string& arg) 
        : member_(arg) 
    {
    }
    std::string& member_;
};

40
2017-08-13 15:37



Người ta thường tin rằng nếu bạn có một thành viên tham khảo, bạn có để định nghĩa một hàm tạo với một danh sách khởi tạo hàm dựng. Nhưng điều đó không hoàn toàn đúng. Đơn giản MyClass m = { arg }; cũng sẽ hoạt động tốt. - Johannes Schaub - litb
litb: nhưng sau đó bạn ít nhiều được yêu cầu sử dụng m = {arg}; arent 'bạn? Trong mắt tôi, có thể làm MyClass m (ref) là khá mong muốn. - Skurmedel
@Skurmedel, tôi đồng ý. Nhưng điều đó không có nghĩa đó là cách duy nhất để làm điều đó, tất nhiên. - Johannes Schaub - litb
"nếu bạn gán một giá trị cho chúng trong phần thân của hàm tạo, thì bạn đang gọi hàm tạo bản sao" Không, bạn không có. Toán tử gán bản sao khác với trình tạo bản sao. - Ben Voigt
Câu trả lời này là sai. Tôi bỏ phiếu để xóa nó. Mọi người nên -1 nó. Rõ ràng, nó gây ra sự nhầm lẫn cho người mới (stackoverflow.com/questions/28529416/…). - thang


Nó biểu thị sự khởi đầu của một danh sách khởi tạo, đó là cho các biến thành viên khởi tạo của đối tượng của bạn.

Giống như là: MyClass(m_classID = -1, m_userdata = 0);

Điều đó tuyên bố một hàm tạo có thể lấy đối số (vì vậy tôi có thể tạo MyClass sử dụng MyClass m = MyClass(3, 4), điều này sẽ dẫn đến m_classID là 3, và m_userdata là 4). Nếu tôi không vượt qua được đối số nào MyClass constructor, nó sẽ dẫn đến một đối tượng tương đương được tạo ra cho phiên bản với danh sách initialiser.


2
2017-08-13 15:25





Nó báo hiệu sự khởi đầu của một danh sách khởi tạo.

Ngoài ra nó không tương đương với MyClass (m_classId = -1, m_userData = 0). Điều này đang cố gắng xác định một hàm tạo với 2 tham số có giá trị mặc định. Tuy nhiên các giá trị thiếu các loại và nó không nên biên dịch ở tất cả.


2
2017-08-13 15:27





nó là một danh sách khởi tạo. Trong ví dụ của bạn, nó là một cái gì đó như thế này (một cái gì đó như thế này - không có nghĩa là nó tương đương trong mọi trường hợp):


class MyClass {

public:

    MyClass(){
         m_classID = -1;
         m_userdata = 0;
    }

    int m_classID;
    void *m_userdata;

};

1
2017-08-13 15:26





Đó được gọi là danh sách khởi tạo thành viên. Nó được sử dụng để gọi các siêu constrctors, và cung cấp cho các biến thành viên của bạn một giá trị ban đầu tại thời điểm chúng được tạo ra.

Trong trường hợp này, nó đang khởi tạo m_classID đến -1 và m_userData thành NULL.

Nó không hoàn toàn tương đương với việc gán vào phần thân của hàm tạo, bởi vì sau này tạo ra các biến thành viên, sau đó gán cho chúng. Với việc khởi tạo, giá trị ban đầu được cung cấp tại thời điểm tạo, vì vậy trong trường hợp các đối tượng phức tạp, nó có thể hiệu quả hơn.


1
2017-08-13 15:27



Đôi khi cũng phải sử dụng danh sách khởi tạo thành viên. Nếu bạn có biến thành viên là tham chiếu, bạn phải đặt biến đó bằng danh sách khởi tạo thành viên. - Skurmedel


Nó không chính xác là một nhà điều hành. Đó là một phần của cú pháp cho một hàm tạo.

Những gì nó nói là sau đây nó sẽ là một danh sách các biến thành viên và giá trị ban đầu của họ.

Các thành viên liên tục phải được khởi tạo theo cách này. Các hằng số không thể được khởi tạo ở đây, miễn là nó có thể được thực hiện với một biểu thức duy nhất. Nếu cần nhiều mã hơn để khởi tạo thành viên, bạn phải đặt mã thực sự giữa {} để thực hiện.

Rất nhiều người thích đặt khá nhiều mã xây dựng của họ trong danh sách initilizer. Tôi có một đồng nghiệp thường xuyên viết các lớp học với một số màn hình của initilizers, và sau đó đặt "{}" cho mã của hàm tạo.


1
2017-08-13 15:28





Bắt đầu của một danh sách khởi tạo thiết lập các biến thành viên trong khi xây dựng đối tượng. Ví dụ của bạn "MyClass (m_classID = -1, m_userdata = 0);" là không thể vì bạn chưa định nghĩa hàm tạo chính xác và bạn sẽ không thể truy cập vào các biến thành viên trong danh sách tham số anyway ... bạn có thể có một cái gì đó như:

MyClass( int classId = -1, void* userData = 0 ) : m_classID(classId), m_userdata(userData) {}

Danh sách khởi tạo được xem là tốt hơn:

MyClass( int classId = -1, void* userData = 0 ) {
    m_classID = classId;
    m_userdata = userData;
}

Google để biết thêm thông tin.


1
2017-08-13 15:29





Trong trường hợp này: Có, ist là tương đương vì chỉ có các kiểu nguyên thủy có liên quan.

Nếu các thành viên là các lớp (cấu trúc) thì bạn nên chọn danh sách khởi tạo. Điều này là bởi vì nếu không thì các đối tượng được xây dựng mặc định và sau đó được gán.


0
2017-08-13 15:25