2014-07-20 13 views
5

Trong C++ chúng ta có thể chuyển đổi con trỏ lớp con thành cha mẹ, nhưng có cách nào để chuyển đổi nó trở lại: từ cha mẹ, được lấy từ con, cung cấp lớp con?C++ Đa hình: từ lớp cha thành con

Ý tôi là:

class Parent 
{ 
    ... 
}; 

class Child : public Parent 
{ 
    ... 
}; 

int main(int argc, char const *argv[]) 
{ 
    Child* child = new Child(); 
    Parent* parent = child; 
    Child* old_child = parent; // how to do this?? 
    return 0; 
} 

Cảm ơn bạn đã trả lời của bạn.

+2

'Child * old_child = dynamic_cast (mẹ); ' – juanchopanza

+2

Yes. ['static_cast <>' và 'dynamic_cast <>'] (http://stackoverflow.com/questions/28002/regular-cast-vs-static-cast-vs-dynamic-cast) có thể được sử dụng để làm điều này. –

+0

Cảm ơn rất nhiều !!! – user2160982

Trả lời

9

"nhưng có cách nào để chuyển đổi lại: từ cha mẹ, được lấy từ trẻ, cung cấp lớp con?"

Có, như đã đề cập trong các câu trả lời khác, có hai cách để thực hiện việc này.

Child * old_child = dynamic_cast<Child*>(parent); 

Kết quả của dynamic_cast<> thể được kiểm tra trong thời gian chạy, do đó bạn có thể xác định xem đối tượng parent thực sự đại diện cho một trường hợp Child:

if(!old_child) { 
    // parent is not a Child instance 
} 

Cũng lưu ý để có được điều này hoạt động bình thường, các lớp trong câu hỏi cần phải có một vtable, rằng RTTI thực sự có thể xác định mối quan hệ của họ.Hình thức đơn giản nhất để đạt được điều này, là cho lớp Parent một hàm destructor ảo

class Parent { 
public: 
    virtual ~Parent() {} 
    // or 
    // virtual ~Parent() = default; 
    // as suggested for latest standards 
}; 

LƯU Ý:
Nếu đây nên áp dụng cho một quyết định thiết kế chung, tôi sẽ mạnh mẽ bỏ qua nó. Thay vào đó, hãy sử dụng pure virtual interfaces để đảm bảo được triển khai hoặc không.


Cách thứ hai của static_cast<> có thể được sử dụng trong các môi trường, nơi bạn cũng biết rằng parent thực sự là một đứa trẻ. Hình thức đơn giản của việc này là CRTP, nơi Parent mất lớp kế thừa như một mẫu tham số

template <class Derived> 
class Parent { 

    void someFunc() { 
     static_cast<Derived*>(this)->doSomething(); 
    } 
}; 

class Child : public Parent<Child> { 
public: 
    void doSomething(); 
}; 

Hiệu lực của một instatiation của Parent<>static_cast<> sẽ được kiểm tra tại thời gian biên dịch.

LƯU Ý:
lợi thế khác là bạn có thể sử dụng một giao diện cho nguồn gốc mà làm cho sử dụng

  • thành viên lớp tĩnh của Derived
  • typedef 's cung cấp bởi Derived
  • .. các đặc điểm lớp học khác, có thể được kiểm tra tại thời điểm biên dịch
+0

Kết quả của dynamic_cast có thể là ... iff lớp cơ sở là một loại đa hình đúng, hay còn gọi là ít nhất một hàm hoặc cơ sở ảo.Nếu không, nó sẽ giảm xuống static_cast (Nó sẽ được giảm độ mạnh thành static_cast khi có đủ chính xác trong mọi trường hợp). – Deduplicator

+0

@Deduplicator THX! Tốt hơn rồi? –

+1

Có, +1. BTW: Sử dụng '= mặc định;' thay vì '{}' cho thân dtor có thể dài hơn một chút nhưng không ngăn cản lớp không tầm thường, với tất cả các lợi ích (mặc dù nó cần trình biên dịch hiện đại hơn một chút). – Deduplicator

2

Bạn cần phải cast đối tượng quay lại con. Này được thực hiện như thế này:

Child * old_child = static_cast<Child*>(parent); 

Child * old_child = dynamic_cast<Child*>(parent); 
+3

Bạn có muốn giải thích thêm một chút về sự khác biệt và hành vi thực tế của hai phương thức truyền này không. –

2
int main() { 
    Parent parent; 
    Child child; 

    // upcast - implicit type cast allowed 
    Parent *pParent = &child; 

    // downcast - explicit type case required 
    Child *pChild = (Child *) &parent; 
} 

Bạn nên sử dụng dynamic_cast để làm điều này một cách an toàn:

Child *p = dynamic_cast<Child *>(pParent) 

EDIT

Với dynamic_cast trả về một con trỏ rỗng nếu loại không nằm ngoài lớp cơ sở, cũng truyền tới tham chiếu ném một ngoại lệ bad_cast. dynamic_cast đặc biệt hữu ích nếu bạn không biết loại đối tượng sẽ là gì.

Mặt khác static_cast:

Child *p = static_cast<Child *>(pParent) 

này giả định rằng bạn muốn thay đổi một chuyển đổi rõ ràng và thực hiện không có kiểm tra thời gian chạy. Điều này cho phép sự linh hoạt nhưng phải được sử dụng thận trọng.

Các yếu hèn thường xuyên hiển thị ở trên:

Child *pChild = (Child *) &parent; 

Là một C-phong cách xuống dàn diễn viên (giống như một static_cast), mà cũng có thể cast vào một lớp học tin cơ sở (không chắc chắn về, đa kế thừa), trong khi static_cast sẽ gây ra lỗi biên dịch. Những thứ như số chuyển đổi là một ví dụ hay để sử dụng tính năng này.

+0

câu trả lời cập nhật để giải thích một chút về các vấn đề an toàn –

0

Câu trả lời ở trên là tốt, khái niệm bạn có thể nghĩ như thế này,

Đối tượng Car của bạn có nguồn gốc từ lớp Vehicle. Bạn có thể tham khảo Car làm Vehicle và có thể chuyển đổi thành Car vì ban đầu nó thuộc về Car. Nhưng nó sẽ là một vấn đề nếu đối tượng Vehicle của bạn thực sự đại diện cho Bike và cố gắng chuyển đổi thành Car. Đó là lý do tại sao bạn cần đúc an toàn.

class Vehicle 
{ 
    ... 
}; 

class Car : public Vehicle 
{ 
    ... 
}; 

class Bike : public Vehicle 
{ 
    ... 
}; 


int main(int argc, char const *argv[]) 
{ 
    Vehicle* vehicle = new Car(); 
    Car* old_car = dynamic_cast<Car *>(vehicle); 
    if(old_car) { 
     // OK Vehicle is Car, use it 
    } 

    vehicle = new Bike(); 
    old_car = dynamic_cast<Car *>(vehicle); 
    if(old_car) { 
     // No Vehicle isn't Car, this code won't execute 
    } 

    return 0; 
} 
+1

Câu trả lời này cho biết thêm bất kỳ giá trị nào so với các câu trả lời khác, ngoài việc thay thế 'Parent' /' Child' bằng phép ẩn dụ 'Vehicle' /' Car'? –

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