2014-12-03 14 views
5

Tôi vừa bắt gặp this question đó là khoảng cách để có thể in một đối tượng thông quaC++ là gì sai với việc sử dụng() phương pháp

std::cout << x << std::endl; 

Như tôi hiểu, cách tiêu chuẩn để thực hiện điều này là một toString quá tải ostreams < < nhà điều hành. Tuy nhiên, điều này là thêm một tính năng vào ostream thay vì cho lớp của tôi.

Cách thay thế (cũng được đưa ra làm câu trả lời cho câu hỏi được đề cập ở trên) là ghi đè toán tử chuyển đổi chuỗi. Tuy nhiên, điều này đi kèm với cảnh báo dẫn đến "chuyển đổi không chủ ý và các lỗi khó theo dõi".

Bây giờ tôi tự hỏi, nếu có bất kỳ hạn chế của việc viết một phương thức toString() và sau đó sử dụng nó thông qua

std::cout << x.toString() << std::endl; 
+0

Làm thế nào bạn sẽ làm điều đó cho một 'int'? Hoặc bạn có nghĩa là 'to_string'? – doctorlove

+0

Bởi vì làm cho một cái gì đó có thể stream được không giống như chuyển đổi nó thành một chuỗi. Nếu bạn muốn loại của bạn được streamable, quá tải 'ostream & operator <<'. Nếu bạn muốn tạo chuỗi từ nó, hãy cho nó một thành viên to_string. – juanchopanza

Trả lời

3

Luồng đầu ra xử lý định dạng đầu ra cũng như đầu ra. Vì vậy, với phương pháp toString() khách hàng của bạn sẽ không thể để quản lý các định dạng cho các đối tượng theo cách mà họ làm cho mọi thứ khác:

// set specific formatting options for printing a value 
std::cout << std::scientific << std::setprecision(10) << 10.0 << '\n'; // prints 1.0000000000e+01 

// set formatting based on user's cultural conventions 
std::cout.imbue(std::locale("")); 
std::cout << 10000000 << '\n'; // depending on your system configuration may print "10,000,000" 

Có lẽ bạn không quan tâm để cho phép bất kỳ định dạng vì vậy có lẽ điều này sẽ không thành vấn đề .

Một lưu ý khác là xuất ra luồng không yêu cầu toàn bộ chuỗi biểu diễn nằm trong bộ nhớ cùng một lúc, nhưng phương thức toString() của bạn.


Những người khác đã chỉ ra điều này, nhưng tôi nghĩ một cách rõ ràng hơn về nói rằng nó là giao diện các lớp học của bạn không chỉ giới hạn trong phương pháp nó cung cấp, mà còn bao gồm các chức năng khác mà bạn xây dựng xung quanh nó, bao gồm cả phi các hàm -member như quá tải operator<< mà bạn cung cấp. Mặc dù nó không phải là một phương pháp của lớp học của bạn, bạn vẫn nên nghĩ về nó như là một phần của giao diện lớp học của bạn.

Dưới đây là một bài báo rằng cuộc đàm phán về vấn đề này mà có lẽ bạn sẽ thấy hữu ích: How Non-Member Functions Improve Encapsulation


Dưới đây là một ví dụ đơn giản của quá tải operator<< cho một người sử dụng lớp định nghĩa:

#include <iostream> 

struct MyClass { 
    int n; 
}; 

std::ostream &operator<< (std::ostream &os, MyClass const &m) { 
    for (int i = 0; i < m.n; ++i) { 
    os << i << ' '; 
    } 
    return os; 
} 

int main() { 
    MyClass c = {1000000}; 
    std::cout << c << '\n'; 
} 
+0

còn các lớp trừu tượng thì sao? Tôi có thể có một toString() = 0; nhưng làm thế nào để tôi tuyên bố rằng bất kỳ lớp học trẻ em nên đi kèm với một toán tử << quá tải? – user463035818

+0

có lẽ tôi nên có lần đầu tiên đọc các liên kết bạn đăng;) Có điểm đầu tiên của nó nói rằng "nếu (f cần phải được ảo) làm cho f một chức năng thành viên". – user463035818

+0

@ tobi303 Vâng, hiện tại các chức năng ảo phải là thành viên. Có thể các hàm không phải thành viên có thể được hỗ trợ cho công văn ảo trong tương lai: http: // www.stroustrup.com/multimethods.pdf – bames53

1

Giả định đầu tiên của bạn là sai. Bạn không cần thực hiện bất kỳ thay đổi nào trong ostream.

Phương thức toán tử như toán tử < < có thể được xác định theo hai cách: Là phương pháp của lớp ostream, lấy đối tượng x làm tham số hoặc hàm cũ cũ với hai tham số. tham số và đối tượng x của bạn làm tham số thứ hai.

4

Như tôi đã hiểu, cách tiêu chuẩn để thực hiện việc này là quá tải các nhà điều hành mạng < <. Tuy nhiên, điều này là thêm một tính năng vào ostream thay vì cho lớp của tôi.

Và đây là điều tốt. Lớp học của bạn càng nhỏ càng tốt. Nếu thành ngữ C++ phổ biến cho phép bạn có thêm một thứ nữa trong lớp của bạn thì tại sao không theo nó?

Bây giờ tôi tự hỏi, nếu có bất kỳ hạn chế của văn bản() phương pháp một toString

Những nhược điểm là:

  • operator<< tác phẩm theo cách thống nhất với các loại dựng sẵn (như int) và các loại do người dùng định nghĩa. toString chỉ có thể có sẵn cho các lớp học
  • C++ không đồng nhất hơn Java. std :: string là chuỗi phổ biến nhất, nhưng vẫn tồn tại các lớp chuỗi khác và chúng được sử dụng.
  • chuỗi phải được tạo, có khả năng có thể đi kèm với lần truy cập hiệu suất. Nếu bạn viết trực tiếp, bạn tránh nó.
+0

Những khuyết điểm này có trọng lượng ít hơn nhiều so với những ưu điểm của việc có một phương pháp tuần tự đồng bộ được encapuslated với bất kỳ lớp nào. Tại sao chúng ta nên quan tâm đến thực hành xấu như không sử dụng std :: string? –

0

Không có gì sai với hàm toString() cho mỗi lớp. Nó có lợi thế là rõ ràng hơn, nó có thể được tạo thành đa hình và nó có thể được sử dụng trong các tình huống khác ngoài luồng, nhưng bạn cần phải có một quy tắc mã hóa khi làm việc với một nhóm ("nó là to_string(), hoặc str() , hoặc streaming()? ").

Nhà điều hành quá tải < < có nhiều thành ngữ hơn. Nó chỉ lấy ostream như tham số và làm cho chuyển đổi ẩn đi khi phát trực tuyến, nhưng vì đây là thành ngữ trong C++, hầu hết sẽ mong đợi một toán tử quá tải < < khi nhìn thấy std::cout << x;.

3

Chúng cơ bản là những thứ khác nhau. Việc cung cấp tình trạng quá tải operator<< có hiệu quả kéo dài giao diện của luồng, làm cho các đối tượng thuộc loại lớp của bạn có thể phát trực tuyến. Cung cấp chức năng toString mở rộng giao diện của lớp học, giúp bạn có thể nhận được một số std::string từ lớp học của mình. Chúng đại diện cho những thứ khác nhau.

Giao diện của lớp học phải hoàn toàn tương ứng với những gì nó đại diện trong logic chương trình của bạn (trách nhiệm duy nhất). Hiếm khi là toString một phần tự nhiên của giao diện của lớp học. Tuy nhiên, việc mở rộng giao diện của luồng để chấp nhận nhiều đối tượng hơn là hợp lý hơn nhiều.

Tức là, trong một trường hợp bạn đang nói "Bây giờ bạn có thể truyền các đối tượng thuộc loại lớp này". Trong trường hợp khác bạn đang nói "Bạn có thể biến đối tượng của loại lớp này thành một số std::string". - nó chỉ xảy ra khi mà std::string sau đó có thể phát trực tuyến. Hãy suy nghĩ về nó - nó thực sự có ý nghĩa đối với lớp học Person của tôi để có một hàm toString? Từ khi nào tôi có thể biến mọi người thành văn bản?

+3

Tôi đoán liệu nó có hợp lý hay không là vấn đề về hương vị. Theo tôi, hoàn toàn có ý nghĩa rằng bất kỳ đối tượng Java nào cũng có thể được chuyển đổi thành một chuỗi thông qua toString() – user463035818

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