2012-06-20 23 views
5

Tôi đang cố gắng khám phá lớp có nguồn gốc xuất phát nhất của một đối tượng, bên trong một hàm tạo của một trong các lớp trong cây thừa kế của nó. Tôi đã dành vài giờ vào việc này ngay bây giờ và đang thua lỗ vì làm cách nào khác tôi có thể làm điều đó hoặc tại sao nó không có ý nghĩa. Nó có vẻ có ý nghĩa hoàn hảo, nhưng nó từ chối làm việc. Tôi đã tìm thấy rất nhiều trang về RTTI và về cơ bản không có nơi nào với chúng. Tôi sẽ tiếp tục giải thích sau khi trường hợp thử nghiệm của tôi và đầu ra của nó.Con trỏ "này" có được bật RTTI không?

Nguồn:

#include <iostream> 
#include <typeinfo> 
#include <string> 

class A 
{ 
public: 
    A(std::string foo); 

    virtual void bar(A* a) = 0; 
}; 

class B : public A 
{ 
public: 
    B(); 

    virtual void bar(A* a); 
}; 

A::A(std::string foo) 
{ 
    std::cout << "type as passed to A constructor: " << foo << " (" << this << ")" << std::endl; 
    std::cout << "type as determined in A constructor: " << typeid(*this).name() << " (" << this << ")" << std::endl; 
} 

B::B() : A(typeid(*this).name()) 
{ 
    A* a = (A*)this; 
    std::cout << "type as determined in B constructor: " << typeid(*a).name() << " (" << this << ")" << std::endl; 
    this->bar(this); 
} 

void B::bar(A* a) 
{ 
    std::cout << "type as determined in bar: " << typeid(*a).name() << " (" << a << ")" << std::endl; 
} 

int main() 
{ 
    B b; 
    b.bar(&b); 

    return 0; 
} 

Sản lượng (trên g ++):

type as passed to A constructor: 1B (0x7fff5fbff910) 
type as determined in A constructor: 1A (0x7fff5fbff910) 
type as determined in B constructor: 1B (0x7fff5fbff910) 
type as determined in bar: 1B (0x7fff5fbff910) 
type as determined in bar: 1B (0x7fff5fbff910) 

Tôi đang cố gắng để có được dòng thứ hai của đầu ra để nói "1B" thay vì "1A" . RTTI có bị loại bỏ khỏi "điều này" vì một lý do nào đó mà tôi chưa thể tưởng tượng? Làm thế nào mà không phá vỡ ý tưởng của các chức năng ảo? (Tôi đã thực hiện điều này với các chức năng ảo cho đến khi tôi phát hiện ra tôi đã thực hiện lại một phần của RTTI mà trước đây tôi chưa từng biết đến). để làm điều đó có vẻ như vỡ bằng thiết kế.

+2

tại sao bạn đang cố gắng phát hiện loại? đó là không tốt. điều này nghe giống như một giải pháp (thiếu sót) đã cố gắng cho một thứ khác, cái gì đó khác? –

+0

Alf, tôi đã std :: bản đồ của các loại (std :: strings, trong trường hợp này) cho các đối tượng, với mỗi loại có một đối tượng duy nhất trong bản đồ. Mỗi cá thể của một lớp nhất định có bản đồ riêng của nó, để cho phép các đối tượng mới có thể dễ dàng được thêm vào các đối tượng cốt lõi này và sau đó được truy lục theo loại. (Tôi đã làm điều này với const int và một trang web của các phương pháp ảo trước khi tôi biết RTTI, với thất bại tương đương cho cùng một lý do.) – Grault

Trả lời

4

Bạn không thể làm điều đó vì bạn hiểu sai về động lực liên quan.

Quy tắc là:

Các this trong constructor/destructor của bất kỳ điểm lớp để lớp có constructor/destructor nó được.

Ngoài ra, đây là lý do virtual chức năng gọi constructor không cư xử như bạn thường mong đợi một hàm virtual để làm việc khi sử dụng cử động.

Bạn nên phát hiện loại, sau các nhà xây dựng đã được called.You có thể làm như vậy trong bất kỳ của các hàm thành viên trừ constructor và destructor.

+0

Được rồi, nhưng tại sao điều đó được coi là tốt hơn? Nó có vẻ không trực quan nhất, với tôi. Nó sẽ phá vỡ một số tính năng OO khác? – Grault

0

Hãy xem xét mối quan hệ thừa kế của bạn, bạn đã biết rằng hàm tạo của A sẽ thực hiện trước và sau đó là một trong số B sẽ. Trong constructor của A, đối tượng chưa là B vì nó chưa được xây dựng. Do đó, kiểu động của một đối tượng bên trong một hàm khởi tạo luôn là kiểu của lớp đó và không bao giờ là kiểu của một lớp dẫn xuất. Điều tương tự cũng xảy ra trong các destructors.

Nói cách ngắn gọn, những gì bạn muốn làm không thể được thực hiện tại thời điểm xây dựng.

+0

"hàm tạo của A sẽ thực thi đầu tiên và sau đó là B sẽ". Đó là những gì tôi nghĩ cho đến khi tôi có thể vượt qua "điều này" như là một B vào nhà xây dựng A (được chứng minh ngầm định trong trường hợp thử nghiệm). Bây giờ tôi hiểu dòng chảy là hàm khởi tạo có nguồn gốc cao nhất thực hiện đầu tiên, và mỗi hàm tạo gọi cha mẹ của nó trước khi làm bất cứ điều gì khác. Vì vậy, các cơ quan chạy từ gốc xuống như bạn nói. – Grault

3

Bạn đang thấy hành vi mong đợi. Trong phần thân của một hàm tạo, kiểu của đối tượng đang được xây dựng cũng giống như kiểu của lớp mà hàm tạo đang được thực thi và không phải lớp của lớp dẫn xuất nhất được xây dựng.

Sự bất thường thực sự trong biểu thức typeid(*this) khi được sử dụng trong biểu thức khởi tạo thành viên. Điều này từng là hành vi không xác định trong C++ 03 nhưng điều này đã được thay đổi trong C++ 11 để bạn nhận được kiểu lớp của nhà xây dựng chứ không phải là kiểu đối tượng thực tế chưa được xây dựng.

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