2012-10-22 86 views
6

Tôi đang xây dựng một thiết kế trò chơi đơn giản cho một dự án của tôi. Tôi có các lớp sau:Con trỏ truyền từ kiểu cơ sở đến kiểu con

class Character 
{ 
public: 
    virtual void Display(); 
    virtual void SetParameters(char* param, ...); 
}; 

class NonPlayableCharacter : public Character 
{ 

public: 
    virtual void Display(); 
    virtual void SetParameters(char* paaram, ...); 
    int GetNPCState(); 
} 

Và sau đó tôi có một nhóm lớp học lấy được từ Ký tự hoặc NonPlayableCharacter. Tôi xác định nó như vậy:

std::vector<Character*> _allChar; 

Vấn đề của tôi là tại bất kỳ thời điểm nào tôi muốn thực hiện một số thao tác trên một phần tử của vectơ. Vì vậy, lấy một phần tử ra khỏi vectơ tôi không thể gọi trực tiếp phương thức GetNPCState() vì phần tử trong vectơ thuộc kiểu Character *. Vì vậy, thực hiện việc này:

_allChar[0]->GetNPCState(); 

không hoạt động. Vì vậy, tôi đã cố gắng làm việc đó với dynamic_cast nổi tiếng:

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]); 
test->GetNPCState(); 

Vấn đề với nỗ lực cuối cùng này là GetNPCState() tai nạn vì đối tượng là null, và tôi biết một thực tế (thông qua gỡ lỗi) mà _allChar [0] isn' t null.

+2

Bạn nhận được một con trỏ rỗng khi đối tượng bạn đang cố gắng truyền tới 'NonPlaya bleCharacter' không thực sự là một 'NonPlayableCharacter'. Có lẽ một số đối tượng trong vectơ được lấy trực tiếp từ 'Character'. – jogojapan

+0

Là một sang một bên, tôi làm việc với một thành phần (s) trong đó sử dụng nhiều vectơ của con trỏ. Nó đã gây ra rất nhiều rắc rối cho tôi, vì vectơ này kết thúc đôi khi với con trỏ tới bộ nhớ đã bị xóa, và nó dẫn đến tham nhũng bộ nhớ. Tôi đoán rằng bạn sử dụng một vector con trỏ bởi vì bạn đang sử dụng nó đa hình, và/hoặc các đối tượng được chia sẻ.Trong cả hai trường hợp, tôi sẽ khuyên bạn nên thay đổi vectơ của bạn để giữ kiểu con trỏ được chia sẻ (ví dụ 'std :: shared_ptr') hoặc thay đổi vectơ thành' boost :: ptr_vector' (điều này rất tốt cho cả hai kịch bản). Chúc may mắn với trò chơi! – Dennis

Trả lời

6

Có một số loại phôi trong C++ (4), trong đó 2 là lợi ích ở đây:

  • static_cast giả định rằng bạn biết những gì bạn đang làm
  • dynamic_cast séc, khi chạy , mà bạn "đã đoán" đúng

Lưu ý: đơn giản, là dynamic_cast cũng cho phép cross-phôi và phôi không khớp ng cơ sở ảo.

Có 3 phiên bản của dynamic_cast, thực sự, tuỳ theo tính chất của mục tiêu:

  • nếu mục tiêu là một tài liệu tham khảo (tức dynamic_cast<T&>(u)), sau đó nếu kiểm tra không dynamic_cast ném một ngoại lệ std::bad_cast
  • nếu mục tiêu là một con trỏ (tức dynamic_cast<T*>(p)), sau đó nếu kiểm tra không dynamic_cast trả về một con trỏ null
  • cuối cùng, như một trường hợp đặc biệt, nếu mục tiêu là.210, sau đó dynamic_cast thay vì trả về địa chỉ của toàn bộ đối tượng

Trong trường hợp này, bạn có thể:

  • chuyển từ dynamic_cast<NonPlayableCharacter*>(_allChar[0])->getNPCState() để dynamic_cast<NonPlayableCharacter&>(*_allChar[0]).getNPCState(), và để cho các ngoại lệ truyền
  • kiểm tra kết quả của dàn diễn viên (NonPlayableCharacter* test tại đây) cho không vô hiệu
3

dynamic_cast trả về NULL nếu không thể truyền. Kiểm tra nội dung bên trong _allChar[0]. Bạn có thể thực hiện chức năng như getType() nơi trở về kiểu đối tượng id xác định trước và sau đó sử dụng static_cast:

if (_allChar[0]->getType() == TYPE_NO_PLAYER) { 
    static_cast<NonPlayableCharacter*>(_allChar[0])->getNpcState(); 
} 
5

Sau

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]); 

bạn nên kiểm tra nếu testNULL. Ngay cả khi _allChar[0] không phải là NULL, thì dynamic_cast có thể trả lại NULL nếu đối tượng trỏ đến không phải là NonPlayableCharacter.

Vì vậy, phiên bản chính xác sẽ là:

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]); 
if (test) 
{ 
    test->GetNPCState(); 
} 
2

Bạn cần phải kiểm tra dynamic_cast để thành công. Nó trả về một con trỏ rỗng khi thất bại:

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]); 
if (test) test->GetNCPState(); 

Vấn đề có thể là phần tử đầu tiên của bạn không trỏ đến đối tượng NonPlayableCharacter.

2

dynamic_cast lợi nhuận NULL khi đối số của nó không trỏ đến một NonPlayableCharacter (do các yếu tố đầu tiên trong mảng có thể chỉ ra một số lớp con khác của Character) - vì vậy bạn cần phải kiểm tra cho NULL sau khi các diễn viên. Tuy nhiên, việc sử dụng dynamic_cast có thể là dấu hiệu của một vấn đề thiết kế. Có lẽ bạn nên có phương pháp ảo trên Character được gọi là ví dụ: PerformMainActionInGameLoop() và được ghi đè thích hợp trong các lớp con khác nhau?

2

Để nhận con trỏ con trỏ từ con trỏ cơ sở, bạn phải sử dụng dynamic_cast.hành vi của nó như sau:

  • Nếu điểm con trỏ đến một Child* giao new Child sau đó dynamic_cast<Child*> trả về một Child*
  • Nếu điểm con trỏ đến cái gì khác, sau đó trở về dynamic_castNULL.

Vấn đề của bạn là bạn không phân bổ với new hoặc đối tượng của bạn thuộc loại khác.

2

Có thể có giải pháp OO tốt hơn để sử dụng dynamic_cast, nhưng toàn bộ điểm sử dụng dàn diễn viên này là nó sẽ trả về con trỏ NULL nếu diễn viên không thành công.

Vì vậy, hãy kiểm tra NULL trước khi bạn gọi GetNPCState();

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]); 
if(test != NULL) 
{ 
    test->GetNPCState(); 
} 
Các vấn đề liên quan