2011-12-20 55 views
11

Tôi đang cố gắng khai báo một mảng với một lớp tùy chỉnh. Khi tôi thêm một hàm tạo vào lớp, trình biên dịch của tôi phàn nàn rằng có "Không có hàm tạo phù hợp để khởi tạo tên [3]".Làm cách nào để khai báo một mảng với một lớp tùy chỉnh?

Dưới đây là chương trình của tôi:

#include <iostream> 

using namespace std; 

class name { 
    public: 
    string first; 
    string last; 

    name(string a, string b){ 
    first = a; 
    last = b; 
    } 
}; 

int main (int argc, const char * argv[]) 
{ 

    const int howManyNames = 3; 

    name someName[howManyNames]; 

    return 0; 
} 

tôi có thể làm gì để thực hiện hoạt động này, và những gì tôi làm sai?

Trả lời

16

Bạn phải cung cấp hàm tạo mặc định. Trong khi bạn đang ở đó, sửa chữa nhà xây dựng khác của bạn, quá:

class Name 
{ 
public: 
    Name() { } 
    Name(string const & f, string const & l) : first(f), last(l) { } 
    //... 
}; 

Ngoài ra, bạn phải cung cấp initializers:

Name arr[3] { { "John", "Doe" }, { "Jane", "Smith" }, { "", "" } }; 

Sau đó là khái niệm thích hợp hơn, vì không có lý do mà lớp học của bạn nên có khái niệm trạng thái "mặc định". Trong trường hợp đó, bạn chỉ cần để cung cấp bộ khởi tạo thích hợp cho mọi phần tử của mảng.

Đối tượng trong C++ không bao giờ ở trạng thái không xác định được; nếu bạn nghĩ về điều này, mọi thứ sẽ trở nên rất rõ ràng.


Một cách khác là sử dụng một động container, mặc dù điều này là khác với những gì bạn yêu cầu:

std::vector<Name> arr; 
arr.reserve(3); // morally "an uninitialized array", though it really isn't 

arr.emplace_back("John", "Doe"); 
arr.emplace_back("Jane", "Smith"); 
arr.emplace_back("", ""); 

std::vector<Name> brr { { "ab", "cd" }, { "de", "fg" } }; // yet another way 
+0

PODs có thể được trong tình trạng mập mờ;) – fredoverflow

+1

@FredOverflow: Chúng không phải "mập mờ" - chúng "chưa được khởi tạo", mà là khái niệm được xác định rõ ràng, với ngữ nghĩa mà bạn không được đọc chúng. –

+0

Được rồi, vậy điều gì sẽ là một ví dụ về cái gì đó * có thể * ở trong trạng thái không xác định? – fredoverflow

3

Bạn cần parameterless constructor để có thể tạo một phiên bản lớp học của mình. Phương thức khởi tạo hiện tại của bạn yêu cầu hai tham số chuỗi đầu vào.

Thông thường C++ ngụ ý có một hàm tạo (= constructor không tham số mặc định) nếu có không có hàm tạo khác nào được khai báo. Bằng cách khai báo hàm tạo đầu tiên của bạn với hai tham số, bạn ghi đè hành vi mặc định này và bây giờ bạn phải khai báo hàm khởi tạo này một cách rõ ràng.

Dưới đây là đoạn code làm việc: (. BTW, bạn cần phải bao gồm để làm cho compilable đang)

#include <iostream> 
#include <string> // <-- you need this if you want to use string type 

using namespace std; 

class name { 
    public: 
    string first; 
    string last; 

    name(string a, string b){ 
    first = a; 
    last = b; 

    } 

    name() // <-- this is your explicit parameterless constructor 
    {} 

}; 

int main (int argc, const char * argv[]) 
{ 

    const int howManyNames = 3; 

    name someName[howManyNames]; 

    return 0; 
} 

Một cách khác là để khởi tạo các trường hợp của bạn một cách rõ ràng về kê khai

name someName[howManyNames] = { {"Ivan", "The Terrible"}, {"Catherine", "The Great"} }; 
4

Để mặc định khởi tạo một mảng của T s, T phải constructible mặc định . Thông thường trình biên dịch cung cấp cho bạn một hàm tạo mặc định miễn phí. Tuy nhiên, vì bạn đã tự khai báo một hàm tạo, trình biên dịch không tạo ra một hàm tạo mặc định.

lựa chọn của bạn:

  • thêm một constructor mặc định để tên, nếu điều đó có ý nghĩa (Tôi không nghĩ như vậy, nhưng tôi không biết lĩnh vực vấn đề);
  • khởi tạo tất cả các phần tử của mảng khi khai báo (bạn có thể làm điều này vì name là tổng hợp);

    name someName[4] = { { "Arthur", "Dent" }, 
             { "Ford", "Prefect" }, 
             { "Tricia", "McMillan" }, 
             { "Zaphod", "Beeblebrox" } 
            }; 
    
  • sử dụng một std::vector thay vào đó, và chỉ làm tăng thêm yếu tố khi bạn đã cho họ xây dựng.

1

bạn chỉ cần thêm một constructor mặc định lớp học của bạn trông như thế này:

class name { 
    public: 
    string first; 
    string last; 

    name() { 
    } 

    name(string a, string b){ 
    first = a; 
    last = b; 
    } 
}; 
1

lớp học của bạn:

class name { 
    public: 
    string first; 
    string last; 

    name() { } //Default constructor. 

    name(string a, string b){ 
    first = a; 
    last = b; 
    } 
}; 

Có một rõ ràng constructor mà đòi hỏi hai chuỗi thông số. Các lớp không có hàm tạo được viết rõ ràng sẽ nhận các hàm tạo mặc định không tham số. Thêm một trình duyệt rõ ràng đã ngăn trình biên dịch tạo ra hàm tạo mặc định đó cho bạn. Vì vậy, nếu bạn muốn tạo một mảng các đối tượng chưa được khởi tạo, hãy thêm một hàm tạo mặc định vào lớp của bạn để trình biên dịch biết cách tạo chúng mà không cung cấp hai tham số chuỗi đó - xem dòng chú thích ở trên.

1

Để tạo một mảng đối tượng, các đối tượng cần một hàm tạo không lấy bất kỳ tham số nào (tạo ra biểu mẫu mặc định của đối tượng, ví dụ: với cả hai chuỗi trống). Đây là ý nghĩa của thông báo lỗi. Trình biên dịch tự động tạo ra một hàm tạo để tạo ra một đối tượng rỗng trừ khi có bất kỳ hàm tạo nào khác.

Nếu nó có ý nghĩa đối với các phần tử mảng được tạo ra có sản phẩm nào (trong trường hợp các thành viên tiếp thu các giá trị mặc định của họ, trong trường hợp này, chuỗi rỗng), bạn nên:

-Viết một constructor rỗng:

class name { 
    public: 
    string first; 
    string last; 

    name() { } 
    name(string a, string b){ 
    first = a; 
    last = b; 
    } 
}; 

-Hoặc, nếu bạn không cần, hãy loại bỏ hàm tạo hiện có.

Nếu phiên bản "trống" của lớp bạn không có ý nghĩa, không có giải pháp tốt để cung cấp thông số khởi tạo cho tất cả các phần tử của mảng tại thời gian biên dịch. Bạn có thể:

  • Có một constructor tạo ra một phiên bản trống rỗng của lớp dù sao, và một chức năng init() mà hiện khởi động thực
  • Sử dụng một vector, và trên khởi tạo các đối tượng và chèn chúng vào vector, hoặc sử dụng vector::insert hoặc vòng lặp và tin tưởng rằng không làm việc đó vào thời gian biên dịch không quan trọng.
  • Nếu không thể sao chép đối tượng, bạn có thể sử dụng mảng/vectơ của con trỏ thông minh cho đối tượng và phân bổ chúng khi khởi tạo.
  • Nếu bạn có thể sử dụng C++ 11 tôi nghĩ (?) bạn có thể sử dụng danh sách initialiser để khởi tạo một vector và intialise nó (tôi không chắc chắn nếu điều đó làm việc với bất kỳ contructor hoặc chỉ nếu đối tượng được tạo ra từ một giá trị duy nhất của loại khác). Ví dụ: .
std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" }; 

'

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