Cách tốt nhất để xắp xếp lại thừa kế tròn ở đây là gì?Kế thừa tròn tò mò với các kết hợp trong C++
class Node {
// ...
public:
list<Node*> neighbors() { /* ... */ }
void update() { }
}
template<class NodeType>
class HasImportance : public virtual NodeType {
double m_importance = 0.0;
public:
void receive_importance(double imp) { /* ... */ }
void give_importance() {
for (auto neighbor : this->neighbors())
neighbor->receive_importance(m_importance /* ... */);
}
};
class TrafficLight : public HasImportance<TrafficLight>, virtual Node {
public:
list<TrafficLight*> neighbors() { ... }
void update() { give_importance(); /* ... */ }
};
Nó thất bại (gcc 4.7.0) vì TrafficLight
là một loại không đầy đủ khi HasImportance
cố gắng để kế thừa từ nó.
Vấn đề thực sự là HasImportance cần phải biết loại trả về neighbors()
. Nếu HasImportance
thừa hưởng từ Node
, sau đó nó nghĩ neighbors()
trả về một danh sách các Node*
, không TrafficLight*
, và hậu quả là không biết rằng nó có thể gọi receive_importance()
vào các mục. Tương tự vấn đề nếu HasImportance
không kế thừa chút nào.
BTW, những gì tôi đang cố gắng thực hiện là một vài kết hợp để giúp xác định nhiều loại khác nhau của các loại đồ thị khác nhau một cách dễ dàng và đơn vị kiểm tra từng kết hợp riêng biệt. Đối với ví dụ , tôi có thể xác định lớp nút cho biểu đồ đèn giao thông bằng cách chỉ viết thứ gì đó như class TrafficLight : public HasImportance, HasState<3>, virtual Node { }
.
Tôi đã đưa ra ba cách để giải quyết vấn đề này, nhưng tất cả đều có vẻ xấu. (1) static_cast<NodeType*>
. (2) TrafficLight
chuyển số this
tới HasImportance
trong hàm tạo của nó. Bằng cách này, HasImportance
không cần phải kế thừa; nó chỉ lưu trữ một con trỏ đến (ahem) và tham số mẫu cung cấp loại con trỏ . (3) Thực hiện Node
một lớp mẫu, như thế này:
template<class NodeType>
class Node {
public:
list<NodeType*> neighbors() { /* ... */ }
}
class TrafficLight : public HasImportance<Node<TrafficLight>> { /* ... */ }
Đó biên dịch và nó không giới thiệu một bản sao nhưng không của this
, nhưng có vẻ như ... một chút quá tò mò.
Có mùi mã ở đây không? Tôi có nên tiếp cận các biểu đồ này theo cách khác hoàn toàn không?
Sử dụng 'static_cast (điều này)' là * bình thường * trong CRTP. –
kennytm
@KennyTM: Tôi thậm chí sẽ đi xa và nói rằng đây là chìa khóa trong việc sử dụng CRTP – PlasmaHH
Cảm ơn bạn. Tôi cringe lúc sử dụng static_cast, bởi vì nó có vẻ như tôi đang bỏ qua một dấu hiệu (một "mùi") mà cái gì sâu sắc hơn là sai. Nếu nó là "bình thường" trong CRTP, tôi đoán tôi sẽ không cưỡng lại quá nhiều. Đây là CRTP đầu tiên của tôi. Bạn có thể nói? :) –