Khởi tạo thành viên trong khi sử dụng hàm tạo được ủy quyền


96

Tôi đã bắt đầu thử tiêu chuẩn C ++ 11 và tôi tìm thấy này câu hỏi trong đó mô tả làm thế nào để gọi ctor của bạn từ một ctor trong cùng một lớp để tránh việc một phương pháp init hoặc tương tự. Bây giờ tôi đang thử điều tương tự với mã giống như sau:

hpp:

class Tokenizer
{
public:
  Tokenizer();
  Tokenizer(std::stringstream *lines);
  virtual ~Tokenizer() {};
private:
  std::stringstream *lines;
};

cpp:

Tokenizer::Tokenizer()
  : expected('=')
{
}

Tokenizer::Tokenizer(std::stringstream *lines)
  : Tokenizer(),
    lines(lines)
{
}

Nhưng điều này đang gây ra lỗi cho tôi: In constructor ‘config::Tokenizer::Tokenizer(std::stringstream*)’: /path/Tokenizer.cpp:14:20: error: mem-initializer for ‘config::Tokenizer::lines’ follows constructor delegationTôi đã thử di chuyển phần Tokenizer () trước và cuối cùng trong danh sách nhưng điều đó không giúp được gì.

Lý do đằng sau điều này là gì và tôi nên sửa nó như thế nào? Thay vào đó, tôi đã thử di chuyển lines(lines)đến cơ thể this->lines = lines;và nó hoạt động tốt. Nhưng tôi thực sự muốn có thể sử dụng danh sách trình khởi tạo.

Câu trả lời:


118

Khi bạn ủy quyền khởi tạo thành viên cho một phương thức khởi tạo khác, có một giả định rằng phương thức khởi tạo kia hoàn toàn khởi tạo đối tượng , bao gồm tất cả các thành viên (tức là bao gồm cả linesthành viên trong ví dụ của bạn). Do đó, bạn không thể khởi tạo lại bất kỳ thành viên nào.

Trích dẫn có liên quan từ Tiêu chuẩn là (tôi nhấn mạnh):

(§12.6.2 / 6) Một mem-khởi tạo-danh sách có thể ủy quyền cho một phương thức khởi tạo khác của lớp của phương thức khởi tạo bằng cách sử dụng bất kỳ kiểu-lớp hoặc kiểu khai báo nào biểu thị chính lớp của phương thức khởi tạo. Nếu một mem-khởi tạo-id chỉ định lớp của hàm tạo, nó sẽ là bộ khởi tạo mem duy nhất ; hàm tạo là một hàm tạo ủy quyền và hàm tạo được chọn bởi hàm là hàm tạo đích. [...]

Bạn có thể giải quyết vấn đề này bằng cách xác định phiên bản của hàm tạo nhận đối số trước :

Tokenizer::Tokenizer(std::stringstream *lines)
  : lines(lines)
{
}

và sau đó xác định hàm tạo mặc định bằng cách sử dụng ủy quyền:

Tokenizer::Tokenizer()
  : Tokenizer(nullptr)
{
}

Theo nguyên tắc chung, bạn nên chỉ định đầy đủ phiên bản của hàm khởi tạo nhận số lượng đối số lớn nhất, rồi ủy quyền từ các phiên bản khác (sử dụng các giá trị mặc định mong muốn làm đối số trong ủy quyền).


2
Thoạt đầu nó có vẻ phản trực quan nhưng thực sự rất hữu ích!
Korchkidu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.