2010-03-27 34 views
6

Tôi muốn chạy 1.000 lần lặp của một chương trình, vì vậy hãy đặt bộ đếm cho 1000 trong chính. Tôi cần phải khởi tạo lại các biến khác nhau sau mỗi lần lặp, và kể từ khi hàm dựng đã có tất cả các khởi tạo đã được viết ra - tôi quyết định gọi sau mỗi lần lặp, với kết quả của mỗi lần lặp được lưu trữ trong một biến trong chính.Gọi một hàm tạo để khởi tạo lại các biến dường như không hoạt động?

Tuy nhiên, khi tôi gọi cho nhà xây dựng, nó không có tác dụng ... tôi mất một thời gian để tìm ra - nhưng nó đã không khởi tạo lại bất cứ điều gì!

Tôi đã tạo một hàm chính xác như hàm tạo - vì vậy đối tượng sẽ có phiên bản riêng của nó. Khi tôi gọi nó, nó đã khởi tạo lại mọi thứ như tôi mong đợi.

int main() 
{ 
Class MyClass() 

int counter = 0; 

while (counter < 1000) 
{ stuff happens } 

Class(); // This is how I tried to call the constructor initially. 
      // After doing some reading here, I tried: 
      // Class::Class(); 
      // - but that didn't work either 
/* Later I used... 
MyClass.function_like_my_constructor; // this worked perfectly 
*/ 
} 

... Ai đó có thể giải thích lý do tôi làm sai hoặc không làm việc hoặc ngớ ngẩn hoặc bạn có gì? Ý tôi là - về mặt tinh thần, tôi chỉ nghĩ - crap, tôi có thể gọi nhà xây dựng này và có tất cả những thứ này được khởi tạo lại. Các hàm tạo (lý tưởng) CHỈ được gọi khi một đối tượng được tạo ra?

+0

Có vẻ như có thể với * vị trí mới *. http://stackoverflow.com/questions/6868363/how-to-recall-a-constructor-of-an-initialised-object – Eonil

+0

'MyClass = Class();'? –

Trả lời

8

Dòng của bạn Class(); gọi hàm tạo của lớp Class, nhưng nó gọi nó là để tạo "đối tượng tạm thời". Vì bạn không sử dụng đối tượng tạm thời đó, dòng này không có tác dụng hữu ích.

Đối tượng tạm thời (thường) biến mất ở cuối biểu thức mà chúng xuất hiện. Chúng hữu ích cho việc truyền đi như các tham số hàm, hoặc khởi tạo các đối tượng khác. Nó gần như không bao giờ hữu ích để chỉ cần tạo một trong một tuyên bố một mình. Ngôn ngữ cho phép nó như là một biểu thức hợp lệ, nó chỉ là cho hầu hết các lớp học nó không làm rất nhiều.

Không có cách nào trong C++ gọi hàm tạo trên đối tượng đã được tạo. Vòng đời của một đối tượng C++ là một công trình và một sự hủy diệt. Đó chỉ là cách nó hoạt động. Nếu bạn muốn thiết lập lại một đối tượng trong suốt cuộc đời của nó, bạn đã làm đúng, đó là gọi một hàm để thiết lập lại nó. Tùy thuộc vào lớp của bạn, bạn có thể không cần phải viết một - toán tử gán mặc định có thể thực hiện chính xác những gì bạn cần. Đó là khi tạm thời có thể có ích:

Class myObject; 
// ... do some stuff to myObject ... 

myObject = Class(); 

Cập nhật này myObject với các giá trị từ tạm thời mới xây dựng. Nó không nhất thiết phải là mã hiệu quả nhất có thể, vì nó tạo ra tạm thời, sau đó sao chép, sau đó phá hủy tạm thời, thay vì chỉ thiết lập các trường thành giá trị ban đầu của chúng. Nhưng trừ khi lớp học của bạn là rất lớn, nó không chắc rằng làm tất cả những gì 1000 lần sẽ mất một số lượng đáng chú ý của thời gian.

lựa chọn khác là chỉ để sử dụng một thương hiệu đối tượng mới cho mỗi lần lặp:

int main() { 
    int counter = 0; 
    while (counter < 1000) { 
     Class myObject; 
     // stuff happens, each iteration has a brand new object 
    } 
} 

Lưu ý rằng Class MyClass(); không không xác định một đối tượng kiểu Class, gọi MyClass, và xây dựng nó không có tham số. Nó khai báo một hàm gọi là MyClass, không có tham số và trả về một đối tượng kiểu Class. Có lẽ trong mã thực của bạn, hàm tạo có một hoặc nhiều tham số.

+0

Tôi sử dụng các nhà xây dựng, nhưng tôi hiếm khi vượt qua các tham số, mặc dù tôi biết tôi có thể. Hầu hết thời gian tôi chỉ cảm thấy như tôi nên đặt chúng bên trong constructor trong mã nguồn. Tại sao truyền tham số để thực hiện thông qua chính? – Azoreo

+0

Trong trường hợp đó tôi rất ngạc nhiên khi biên dịch mã của bạn, nếu bạn không sử dụng các tham số hàm tạo nhưng cũng không sử dụng đúng cú pháp cho các hàm tạo parameterless. Dù sao, lý do để sử dụng các tham số constructor là nếu các đối tượng của lớp của bạn không giống nhau. Hãy xem thư viện chuẩn để biết các ví dụ - bạn có thể chỉ định kích thước và nội dung ban đầu của vectơ và v.v. –

+0

Sử dụng Microsoft Visual Studio C++ và nó được xây dựng trong trình biên dịch ... Nếu tôi tuyên bố một nhà xây dựng như KnightsTour :: KnightsTour (ví dụ) và sau đó đặt KnightsTour; trong headerfile của tôi, nó ném lỗi, nói rằng nó trông giống như một hàm, nhưng không có tham số. Soooo ... Tôi đã thêm một danh sách tham số trống, tức là "KnightsTour :: KnightsTour()" và sau đó là "KnightsTour();" trong headerfile - biên dịch và chạy! – Azoreo

1

Có, đây không phải là cách sử dụng thông thường. Tạo một hàm để đặt lại các biến của bạn và gọi phương thức bất cứ khi nào bạn cần.

0

Bạn đã trở thành con mồi của việc hiểu sai C++. C++ 0x mới làm cho mọi thứ rõ ràng hơn một chút.

Vấn đề là cấu trúc cú pháp trông giống như một cuộc gọi hàm.

void foo(int i) { } 
class Foo { }; 

Foo(10); // construct a temporary object of type foo 
foo(10); // call function foo 
Foo{10}; // construct a temporary object of type foo in c++0x syntax 

Tôi nghĩ cú pháp C++ 0x rõ ràng hơn.

Bạn có thể làm những gì bạn muốn với cú pháp này. Nhưng hãy cẩn thận nó là rất tiên tiến và bạn nên không làm điều đó.

MyClass.~Class(); // destruct MyClass 
new(&MyClass) Class; 
+0

Lý do thực tế chính không phải là làm điều này là nếu constructor của 'Class' ném, thì đối tượng' MyClass' đang ở trạng thái không nhất quán. Stack unwinding sẽ cố gắng để phá hủy nó một lần nữa, mang lại hành vi không xác định. Điều đó, và nó không giúp bạn đạt được điều gì hơn một hàm thành viên 'operator =' hoặc 'reset' được viết tốt. Vì vậy, nếu bạn kiểm soát 'MyClass' không cần phải làm điều này, và nếu bạn không kiểm soát' MyClass' thì nó yêu cầu rắc rối ;-) –

5

gì sẽ xảy ra trong dòng đọc ...

Class(); 

Có phải đó là bạn làm trong thực tế gọi các nhà xây dựng - cho một đối tượng tạm thời đang được xây dựng từ đầu, và sau đó được ngay lập tức destructed vì bạn không làm gì với nó. Nó rất giống với việc đúc sang Class, tạo ra một giá trị bằng cách sử dụng một hàm gọi hàm dựng, ngoại trừ trong trường hợp này không có giá trị để đúc sao cho hàm tạo mặc định được sử dụng.

Có thể trình biên dịch sau đó tối ưu hóa tạm thời này, vì vậy không có hàm tạo nào cả - tôi không chắc liệu điều đó có được phép hay không.

Nếu bạn muốn khởi tạo lại thành viên, hãy gọi hàm tạo không phải là cách để thực hiện. Di chuyển tất cả mã khởi tạo của bạn vào một phương thức khác và gọi nó từ hàm tạo của bạn, và khi bạn muốn khởi tạo lại, thay vào đó.

+2

"Tôi không chắc liệu nó có được phép hay không" - đúng vậy, nhưng chỉ khi cả constructor lẫn destructor đều không có bất kỳ ảnh hưởng nào đến hành vi quan sát được của chương trình. Vì vậy, nếu bạn đặt một số truy tìm để xem liệu chúng có bị bỏ qua hay không, thì chúng không thể bỏ qua. –

0

Với các yêu cầu như vậy, tôi thường viết phương thức clear() (công khai). Tôi gọi nó từ constructor, destructor. Mã người dùng có thể gọi nó bất cứ khi nào nó muốn.

class Foo 
{ 
    public: 

    Foo() { clear(); } 

    ~Foo() { clear(); } 

    void clear(); // (re)initialize the private members 

    private: 

    // private members 
}; 

Để trả lời câu hỏi ở đây, phương pháp clear() có thể được gọi bất cứ khi nào nó là cần thiết để tái khởi tạo các lớp như nó đã được chỉ sau khi xây dựng ban đầu.

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