Không nên sử dụng toán tử chuyển đổi ngầm. Trong C++ 11, bạn có thể thêm từ khóa explicit
không chỉ vào các hàm tạo đối số đơn lẻ mà còn cho các toán tử chuyển đổi. Đối với mã C++ 03, bạn có thể sử dụng hàm chuyển đổi được đặt tên rõ ràng như self()
hoặc down_cast()
.
Hơn nữa, bạn dường như đang sử dụng lớp Base
cho CRTP, tức là để bật tính đa hình tĩnh. Điều đó có nghĩa là bạn phải biết tại thời gian biên dịch mà cụ thể là Derived
lớp bạn đang gọi. Do đó, bạn không cần phải sử dụng tài liệu tham khảo const Base&
trong bất kỳ mã công cộng nào, ngoại trừ việc triển khai giao diện CRTP.
Trong các dự án của tôi, tôi có một lớp mẫu enable_crtp
:
#include <type_traits>
#include <boost/static_assert.hpp>
template
<
typename Derived
>
class enable_crtp
{
public:
const Derived& self() const
{
return down_cast(*this);
}
Derived& self()
{
return down_cast(*this);
}
protected:
// disable deletion of Derived* through Base*
// enable deletion of Base* through Derived*
~enable_crtp()
{
// no-op
}
private:
// typedefs
typedef enable_crtp Base;
// cast a Base& to a Derived& (i.e. "down" the class hierarchy)
const Derived& down_cast(const Base& other) const
{
BOOST_STATIC_ASSERT((std::is_base_of<Base, Derived>::value));
return static_cast<const Derived&>(other);
}
// cast a Base& to a Derived& (i.e. "down" the class hierarchy)
Derived& down_cast(Base& other)
{
// write the non-const version in terms of the const version
// Effective C++ 3rd ed., Item 3 (p. 24-25)
return const_cast<Derived&>(down_cast(static_cast<const Base&>(other)));
}
};
Lớp này được tư nhân có nguồn gốc từ bất kỳ ISomeClass lớp cơ sở CRTP như thế này:
template<typename Impl>
class ISomeClass
:
private enable_crtp<Impl>
{
public:
// interface to be implemented by derived class Impl
void fun1() const
{
self().do_fun1();
}
void fun2()
{
self().do_fun2()
}
protected:
~ISomeClass()
{}
};
Các lớp có nguồn gốc khác nhau có thể thực hiện giao diện này theo cách riêng của họ như sau:
class SomeImpl
:
public ISomeClass<SomeImpl>
{
public:
// structors etc.
private:
// implementation of interface ISomeClass
friend class ISomeClass<SomeImpl>;
void do_fun1() const
{
// whatever
}
void do_fun2()
{
// whatever
}
// data representation
// ...
};
Gọi mã bên ngoài fun1
của class SomeImpl
sẽ được chuyển đến phiên bản const hoặc không const thích hợp của self()
trong class enable_crtp
và sau khi down_cast việc triển khai do_fun1
sẽ được gọi. Với một trình biên dịch tốt, tất cả các indirections nên được tối ưu hóa hoàn toàn.
LƯU Ý: các destructors được bảo vệ của ISomeClass
và enable_crtp
làm cho mã an toàn đối với người dùng cố gắng xóa SomeImpl*
đối tượng thông qua con trỏ cơ sở.
Phần có liên quan sẽ là phần có độ phân giải quá tải. –
Nếu bạn hài lòng với sự tò mò của tôi - tại sao bạn muốn toán tử chuyển đổi trong 'Base'? –
@ Tony Delroy: 1) để tiết kiệm hơn một cách rõ ràng gọi phương thức lớp.2) Tôi đã tìm thấy loại mã này một vài lần trên web trong khi cố gắng tìm hiểu về các CRTP, xem ví dụ [tại đây] (http : //en.wikipedia.org/wiki/Expression_templates) 3) Sau khi tìm thấy hành vi kỳ lạ này tôi đã thực sự tò mò mà nên là một trong những chính xác :-) – Massimiliano