2010-09-29 48 views
15

Tôi đang kế thừa một lớp và tôi muốn gọi một trong các hàm tạo của nó. Tuy nhiên, tôi phải xử lý một số thứ (không yêu cầu bất kỳ thứ gì của lớp cơ sở) trước khi gọi nó. Có cách nào tôi chỉ có thể gọi nó sau này thay vì gọi nó trên danh sách initializer? Tôi tin rằng điều này có thể được thực hiện trong Java và C# nhưng tôi không chắc chắn về C + +.Gọi hàm tạo lớp cơ sở sau (không có trong danh sách khởi tạo) trong C++

Dữ liệu mà tôi cần truyền vào hàm tạo không thể được gán lại sau, vì vậy tôi không thể chỉ gọi hàm khởi tạo mặc định và khởi tạo nó sau này.

Trả lời

27

Có cách nào tôi có thể gọi lại sau này thay vì gọi nó trên danh sách bộ khởi tạo không?

Không, bạn không thể. Trình tạo lớp cơ sở phải được gọi trong danh sách khởi tạo, và nó phải được gọi là đầu tiên.

Trong thực tế, nếu bạn bỏ qua nó ở đó, trình biên dịch sẽ chỉ thêm cuộc gọi ngầm.

Tôi tin rằng điều này có thể được thực hiện trong Java và C# nhưng tôi không chắc chắn về C++.

Cả C# lẫn Java cũng không cho phép điều này.

Điều bạn có thể thực hiện, tuy nhiên, gọi phương thức là cuộc gọi hàm tạo cơ sở. Điều này sau đó được xử lý trước khi các nhà xây dựng:

class Derived { 
public: 
    Derived() : Base(some_function()) { } 

private: 
    static int some_function() { return 42; } 
}; 
+1

Cảm ơn, đã không nghĩ đến việc chỉ gọi một hàm, do đó nó sẽ hoạt động nhưng sẽ hơi lộn xộn vì hàm tạo có 2 tham số. Tôi sẽ chấp nhận câu trả lời này khi tôi có thể (trừ khi có một câu trả lời tốt hơn, dĩ nhiên). BTW, bạn nói đúng về việc không thể làm điều này trong Java và C#, tôi nghĩ nó có thể trong Java bởi vì nó được thực hiện bằng cách sử dụng 'super (...)' trên thân phương thức, nhưng bây giờ tôi đã nhận thấy nó phải là dòng đầu tiên. – placeholder

+4

+1 Bạn nên thực hiện some_function() tĩnh để ghi lại thực tế là nó không sử dụng bất kỳ biến cá thể nào của lớp (chưa được khởi tạo). –

+0

Thú vị, chưa bao giờ thấy điều đó được thực hiện trước đây. Tôi cho rằng hàm được gọi có thể là hàm lớp dẫn xuất. – PatrickV

-2
struct base{ 
    base(int x){} 
}; 

struct derived : base{ 
    derived(int x) : base(x){} 
}; 

Đây là cách constructor của lớp cha được gọi trong C++ khỏi danh sách khởi tạo của lớp dẫn xuất.

+4

Đây không phải là những gì anh ta đang hỏi. –

1

IMHO Tôi không nghĩ rằng có thể trì hoãn việc gọi hàm tạo lớp cơ sở theo cách bạn đã đề cập.

0

Ồ, tất cả chúng ta đều trẻ một lần. Câu trả lời này sẽ không hoạt động, do đó, không sử dụng nó. Nội dung còn lại cho mục đích lịch sử.

Nếu bạn có toàn quyền kiểm soát lớp cơ sở, tôi khuyên bạn nên thêm phương thức được bảo vệ để khởi tạo lớp, đặt ảo và đặt chi tiết triển khai lớp dẫn xuất của bạn trước khi gọi cơ sở:

class Base 
{ 
public: 
    Base() 
    { 
     Initialize(); 
    } 
protected: 
    virtual void Initialize() 
    { 
     //do initialization; 
    } 
}; 

class Derived : Base 
{ 
public: 

    Derived() : Base() 
    { 
    } 
protected: 
    virtual void Initialize() 
    { 
     //Do my initialization 
     //call base 
     Base::Initialize(); 
    } 
}; 
+0

Thật không may, tôi không có quyền kiểm soát của lớp cơ sở. – placeholder

+0

Bạn có thể không đạt được mục tiêu của bạn sau đó. Nếu bạn đăng thêm mã, chúng tôi có thể tìm ra thứ gì đó, nhưng tôi chưa bao giờ thấy điều đó được thực hiện trong C++. – PatrickV

+0

Tôi không thích ý tưởng. Việc xây dựng hai pha luôn dễ xảy ra lỗi. – sbi

11

Như đã được một số người trả lời, bạn không thể trì hoãn việc triệu gọi một hàm tạo lớp cơ sở, nhưng Konrad has given a good answer có thể giải quyết tốt vấn đề của bạn. Tuy nhiên, điều này có nhược điểm của nó (ví dụ, khi bạn cần khởi tạo một số hàm với các giá trị có tính toán chia sẻ kết quả trung gian), do đó, để hoàn thành, đây là một cách khác để giải quyết vấn đề thứ tự khởi tạo cố định, sử dụng .

Cho thứ tự cố định khởi tạo, nếu bạn có quyền kiểm soát lớp dẫn xuất (và bạn sẽ làm thế nào để fiddle với một trong các ctors của nó?), Bạn có thể lẻn vào một cơ sở tư nhân để nó sẽ được khởi tạo trước khi cơ sở khác, mà sau đó có thể được khởi tạo với giá trị đã tính toán cơ sở tư nhân:

class my_dirty_little_secret { 
    // friend class the_class; 
public: 
    my_dirty_little_secret(const std::string& str) 
    { 
    // however that calculates x, y, and z from str I wouldn't know 
    } 
    int x; 
    std::string y; 
    float z; 
}; 

class the_class : private my_dirty_little_secret // must be first, see ctor 
       , public the_other_base_class { 
    public: 
    the_class(const std::string str) 
     : my_dirty_little_secret(str) 
     , the_other_base_class(x, y, z) 
    { 
    } 
    // ... 
}; 

Lớp my_dirty_little_secret là một cơ sở riêng để người dùng của the_class không thể sử dụng nó, tất cả nội dung của nó cũng là riêng tư, với tình bạn rõ ràng chỉ cấp quyền truy cập the_class. Tuy nhiên, vì nó được liệt kê đầu tiên trong danh sách lớp cơ sở, nó sẽ được xây dựng một cách đáng tin cậy trước the_other_base_class, vì vậy bất cứ điều gì nó tính toán có thể được sử dụng để khởi tạo điều đó.
Một bình luận tốt đẹp trong danh sách lớp cơ sở hy vọng ngăn chặn những người khác phá vỡ mọi thứ bằng cách tái cấu trúc.

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