2012-08-25 23 views
6

Ví dụ: đề xuất map<int,void*>hold trong đó void* luôn lưu trữ con trỏ từ classA là an toàn để truyền lại sau qua static_cast?Có được phép trỏ static_cast một void *

classA* ptr = static_cast<classA*>(holditerator->second); 

lý do void* được sử dụng là bởi vì hold là thành viên của một lớp được định nghĩa trên một tiêu đề được sử dụng bởi một số tập tin cpp mà không biết classA là gì. Tôi sẽ phải bao gồm tiêu đề của classA định nghĩa trên các tệp cpp này mà không thể thực hiện được bằng nhiều lý do.

+1

Tại sao bạn làm điều này? Vui lòng cung cấp thêm ngữ cảnh vì có khả năng là một giải pháp phù hợp hơn. – Johnsyweb

+0

Tại sao bạn không sử dụng bản đồ ngay từ đầu? – BatchyX

+0

@BatchyX Tôi đoán 'giữ' không chỉ chứa classA *? –

Trả lời

13

Có, static_cast là OK trong trường hợp đó và điều phù hợp để sử dụng.

Tôi phải hỏi tại sao bạn không lưu trữ classA* con trỏ ở vị trí đầu tiên. Nếu bạn muốn đặt con trỏ lớp có nguồn gốc vào nó, sau đó hãy cẩn thận, bạn cần phải upcast/upconvert (ngầm hoặc rõ ràng) các con trỏ lớp dẫn xuất đến classA*trước bạn đặt chúng vào bản đồ. Tuy nhiên, ngay cả khi bạn đặt con trỏ lớp dẫn xuất vào bản đồ, một con trỏ lớp cơ sở sẽ đủ bởi vì một con trỏ lớp dẫn xuất được chuyển đổi hoàn toàn thành một con trỏ lớp cơ sở.

Lý do void * được sử dụng là vì giữ là thành viên của lớp xác định trên tiêu đề được một số tệp cpp sử dụng không biết classA là gì.

Đó có thể là lý do hợp lệ để ngăn chặn vi phạm phân lớp.

Tôi sẽ phải bao gồm tiêu đề của định nghĩa classA trên các tệp cpp này mà không thể thực hiện được bằng nhiều lý do.

Điều đó có thể không nhất thiết trong trường hợp của bạn. Một tờ khai chuyển tiếp đủ. Nếu tiêu đề biết những gì được đưa vào bản đồ, nhưng chỉ muốn tránh bao gồm các tiêu đề bổ sung, đây là cách để đi.

+0

Tôi đã chỉnh sửa câu hỏi –

2

Viết void * trong tiêu đề chỉ vì những người sử dụng bản đồ không nên biết về các loại thực tế là không một ý tưởng tốt, như bạn mất an toàn kiểu ở khắp mọi nơi trong mã của bạn, kể cả ở những nơi mà làm biết về ClassA .

Cân nhắc

  1. bắt nguồn ClassA từ một lớp học mà tất cả các phần của mã của bạn có thể biết về,
  2. gói bản đồ thành một đối tượng cung cấp một giao diện cho những bộ phận của mã mà phải đối phó với bản đồ, nhưng không phải với ClassA,
  3. tuyên bố, nhưng không xác định ClassA lớp trong tệp tiêu đề của bạn (có thể nguy hiểm nếu đối tượng bị hủy ở một số nơi mà ClassA được khai báo, nhưng không được xác định),
  4. sử dụng mẫu,
  5. triển khai lớp chứa bản đồ dưới dạng lớp con có nguồn gốc, sao cho trường bản đồ có thể được đưa vào phân lớp có nguồn gốc.

Point 5: Minh họa (= template mẫu)

Thay vì

class Containing { 
    private: 
     map<int,void*> myMap; 
    public: 
     void somePublicFunction() { // ...implementation } 
}; 

bạn viết

// Containing.h 
class Containing { 
    protected: 
     virtual void doSomething() = 0; 
    public: 
     static Containing* Create(); 
     void somePublicFunction() { doSomething(); } 
     virtual ~Containing() { } 
}; 

// Containing.cc 
#include ContainingImplementation.h 
Containing* Containing::Create() { return new ContainingImplementation; } 

// ContainingImplementation.h/cc 
class ContainingImplementation : public Containing { 
    protected: 
     virtual void doSomething() { // ... } 
    private: 
     map<int,ClassA*> myMap; 
    public: 
     virtual ~ContainingImplementation() { } 
}; 
6

Như Johannes giải thích, các static_cast là ok. Một kỹ thuật khác để ngăn chặn các phụ thuộc vào ClassA trong các tệp cpp là sử dụng pimpl idiom.

// in header file 
class classB { 
public: 
    classB(); 
    ~classB(); 
private: 
    class impl; 
    unique_ptr<impl> pimpl; 
}; 



// in implementation file 
#include "classA.hpp" 

class classB::impl 
{ 
    std::map<int, classA> hold; // hidden in implementation file 
}; 

classB::classB() : pimpl{ new impl{ /*...*/ } } { } 
classB::~classB() { } 
+1

ý tưởng tuyệt vời :) –

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