2013-08-15 39 views
6
class Base 
{ 
public: 
    void operator()() { func(); } 
private: 
    virtual void func() {} 
}; 

class Derived1 : public Base 
{ 
private: 
    void func() override {/*do something*/} 
}; 

class Derived2 : public Base 
{ 
private: 
    void func() override {/*do something else*/} 
}; 

Bởi vì tôi muốn sử dụng toán tử quá tải,
tham khảo là một lựa chọn tốt hơn so với con trỏ.C++ tham khảo lớp cơ sở khởi với đối tượng khác nhau có nguồn gốc lớp

Những gì tôi có ý định làm là như sau:

if (condition) { 
    Base& obj = Derived1(); 
} else { 
    Base& obj = Derived2(); 
} 

Nhưng obj sẽ bị phá hủy và kết thúc của phạm vi.

Base& obj; 
if (condition) { 
    obj = Derived1(); 
} else { 
    obj = Derived2(); 
} 

Sẽ không làm việc, hoặc,
Bởi vì tài liệu tham khảo cần phải được khởi tạo trên tuyên bố.

Nếu tôi cố gắng:

Base& obj = condition ? 
    Derived1() : Derived2(); 

Vẫn còn một lỗi, Bởi vì hành ternary mong đợi kiểu mui trần.

Giải pháp tốt nhất để giải quyết vấn đề này là gì?

Trả lời

4

Bạn không thể sử dụng ?: trong trường hợp này là Derived1 và Derived2 là các loại khác nhau.

Một cách tốt là sử dụng con trỏ, đây là hợp lệ:

condition ? pObj.reset(new Derived1()) : pObj.reset(new Derived2()); 

Hoặc

#include <memory> 
std::unique_ptr<Base> pObj; 
if (condition) 
{ 
    pObj.reset(new Derived1()); 
} 
else 
{ 
    pObj.reset(new Derived2()); 
} 

Bạn có thể gọi operator() theo cách này:

(*pObj)(); 
+0

Sử dụng con trỏ có nghĩa là tôi phải sử dụng obj-> operator(), và mất cú pháp tự nhiên của nhà khai thác quá tải. – gnephiak

+0

xem câu trả lời cập nhật của tôi, bạn không 'phải gọi -> và nó không mất quá tải nhà điều hành – billz

+0

Mặc dù điều này sử dụng con trỏ, vẫn là câu trả lời tốt nhất cho nhu cầu của tôi. – gnephiak

0

này sẽ làm việc:

Base* obj; 
if (condition) { 
    obj = new Derived1; 
} else { 
    obj = new Derived2; 
} 

và sau đó ở phần cuối của mã của bạn, bạn cần phải thêm một

delete obj 
1

Bạn có thể thay đổi mã của bạn như sau

Base *obj1; 
if (condition) { 
    obj1 = new Derived1(); 
} else { 
    obj1 = new Derived2(); 
} 
Base &obj = *obj1; 

Nhưng chắc chắn rằng bạn xóa obj1 sau

1

Nếu bạn muốn tham chiếu, bạn không thể liên kết tạm thời với nó trừ khi đó là const Base &. Điều này có nghĩa là bạn cần một đối tượng thực sự để liên kết với, vì vậy, hãy bắt đầu với điều đó:

Derived1 d1; 
Derived2 d2; 

Bạn có thể tham chiếu không tham chiếu với hàm (bao gồm lambda). Nếu không có sẵn lambdas, một hàm bình thường sẽ cần phải lấy d1d2 làm tham số.

auto choose = [&](bool b) -> Base & { 
    if (b) {return d1;} 
    else {return d2;} 
}; 

Bây giờ tạo obj được dễ dàng:

Base &obj = choose(condition); 
+0

Đây thực sự là một giải pháp làm việc, nhưng với đối tượng thừa. Tôi sẽ chấp nhận câu trả lời của billz là câu trả lời đúng. – gnephiak

+0

@gnephiak, Thật không may, tôi không nghĩ rằng có một cách xung quanh mà không có một số loại con trỏ. Tôi đoán bạn về mặt kỹ thuật có thể sử dụng một con trỏ thông minh và có 'Base & obj = * ptr.get();' và sau đó chắc chắn rằng bạn không sử dụng 'obj' sau khi' ptr' đi ra khỏi phạm vi. – chris

+0

Nếu đối tượng dư thừa là ok (nó nằm trên stack sau khi tất cả), bạn chỉ có thể sử dụng static_cast thay vì lambda hacky: 'Base & obj = condition? static_cast (d1): static_cast (d2); ' – iano