2013-07-08 28 views
5

Tôi có một phân cấp hình kim cương của các lớp, trong đó không có hàm tạo mặc định, cũng không phải các hàm tạo bản sao. Hai nhà xây dựng Tôi có là một "di chuyển" một và khác mà phải mất một tài liệu tham khảo giá trị trái đến một đối tượng:Làm thế nào để thực hiện một hàm tạo di chuyển cho một thừa kế hình kim cương?

struct base { 
    base(base&&) = default; 
    base(member_type&& m): member_(std::move(m)) {} 
    member_type member_; 
}; 

struct virt_1: virtual base { 
    virt_1(virt_1&& rhs): base(std::move(rhs)) {} 
    virt_1(member_type&& m): base(std::move(m)) {} 
}; 

struct virt_2: virtual base { 
    virt_2(virt_2&& rhs): base(std::move(rhs)) {} 
    virt_2(member_type&& m): base(std::move(m)) {} 
}; 

struct concrete: virt_1, virt_2 { 
    concrete(concrete&& rhs) // ??? 
}; 

Bên cạnh đó không sử dụng một hệ thống phân cấp kim cương hình, là nó có thể để thực hiện các constructor di chuyển cho lớp bê tông ?

Cảm ơn!

+1

Âm báo rất dễ xảy ra với tôi. Hàm khởi tạo của cơ sở ảo được gọi từ lớp dẫn xuất nhất, và sẽ không có lý do gì mà nó không thể gọi một hàm khởi tạo (move constructor). Nhưng bất kỳ dẫn xuất xa hơn, và có một cơ hội tốt một người nào đó sẽ quên nó, hoặc làm điều đó sai. Theo nguyên tắc chung, các lớp cơ sở ảo không được chứa dữ liệu hoặc ít nhất có bất kỳ hàm tạo nào khác với một hàm tạo mặc định, để tránh các vấn đề như vậy. –

+0

@ JamesKanze Tôi biết rõ rằng 'cơ sở' không nên chứa dữ liệu, hoặc ít nhất có một hàm tạo mặc định, nhưng nó không thể là trường hợp trong ngữ cảnh của tôi. Tuy nhiên, có cơ hội nào mà trình biên dịch sẽ phàn nàn nếu ai đó quên gọi hàm tạo cơ sở ảo khi phát sinh thêm? – piwi

+0

@piwi, không, không có cơ hội, bởi vì 'base' không có hàm tạo mặc định, vì vậy loại có nguồn gốc cao nhất ** phải ** xây dựng nó rõ ràng –

Trả lời

8

Có vấn đề gì khi yêu cầu trình biên dịch cung cấp triển khai?

concrete(concrete&&) = default; 

Tôi muốn xác định các nhà thầu di chuyển virt_1virt_2 làm mặc định.

Bạn có thể viết nó ra nếu bạn thực sự muốn:

concrete(concrete&& rhs) 
: base(std::move(rhs)), virt_1(std::move(rhs)), virt_2(std::move(rhs)) 
{ } 

Hoặc nếu bạn thực sự thích cách gõ:

concrete(concrete&& rhs) 
    : base(static_cast<base&&>(rhs)), 
     virt_1(static_cast<virt_1&&>(rhs)), 
     virt_2(static_cast<virt_2&&>(rhs)) 
    { } 

Các initializers cho virt_1virt_2 căn cứ là vô ích, bởi vì họ chỉ hãy gọi cho nhà xây dựng base và vì đó là một cơ sở ảo, họ sẽ không làm điều đó khi concrete gọi nó, nhưng do lựa chọn của bạn về các nhà xây dựng, bạn không thể xây dựng chúng mặc định và được yêu cầu khởi tạo chúng rvalue mặc dù họ sẽ không làm gì với nó.

+1

Câu hỏi: điều này có nguy hiểm không? Có vẻ như nó đang di chuyển nhiều lần từ cùng một đối tượng ... –

+0

Tôi nghĩ rằng vấn đề của tôi nằm trong cả hai hàm tạo của lớp bê tông; Tôi sẽ triển vọng với nhà xây dựng di chuyển mặc định – piwi

+1

@AndyProwl, không, xem đoạn cuối cùng tôi đã thêm vào. Phương thức khởi tạo 'base' sẽ chỉ được gọi một lần (bởi hàm tạo cho kiểu dẫn xuất nhất), vì vậy tất cả các hàm tạo khác không thực sự làm bất cứ điều gì với tham số rvalue của chúng. Sẽ chỉ có một động tác (nhớ rằng việc gọi 'std :: move' không thực sự di chuyển bất cứ điều gì, một động thái chỉ xảy ra khi một cái gì đó chấp nhận một tham số rvalue và chọn để di chuyển từ nó.) –

1

Chắc chắn. Bất kỳ hàm tạo nào có cơ sở virtual ở đâu đó trong cấu trúc phân cấp đều chịu trách nhiệm khởi tạo cơ sở đó. Về cơ bản, bất kỳ lớp nào bên dưới cơ sở virtual trong cấu trúc phân cấp thừa hưởng quyền khởi tạo cơ sở.

Trong trường hợp này, hàm tạo di chuyển mặc định sẽ làm điều đúng. Tôi cũng khuyên bạn nên chỉ định concrete : private virtual base để làm rõ điều gì đang xảy ra.

Here là bản trình diễn hoạt động.

+0

Cũng có thể kiểm tra toán tử gán di chuyển. –

+1

Lớp học không phải kế thừa trực tiếp từ cơ sở. Nhưng nó _is_ chịu trách nhiệm gọi các nhà xây dựng của bất kỳ cơ sở ảo nào, ngay cả khi nó không kế thừa từ chúng. –

+0

@JamesKanze Oh, tôi nghĩ rằng đó là một lỗi cú pháp để có một bộ khởi tạo mem cho một cơ sở gián tiếp. Nó không phải. Tuy nhiên, sửa tôi nếu tôi sai, nhưng sự khác biệt chỉ là cú pháp/kiểu. Nó sẽ không tạo ra sự khác biệt nào để thừa kế từ cơ sở, và bất hợp pháp để thừa kế từ cơ sở mà không có 'virtual'. – Potatoswatter

Các vấn đề liên quan