Trong trường hợp nào là tốt hơn để sử dụng struct
so với a class
trong C ++?
Trong trường hợp nào là tốt hơn để sử dụng struct
so với a class
trong C ++?
Câu trả lời:
Sự khác biệt giữa a class
và a struct
trong C ++ là các cấu trúc có public
các thành viên mặc định và các cơ sở và các lớp có private
các thành viên và cơ sở mặc định . Cả lớp và cấu trúc có thể có một hỗn hợp của public
, protected
và private
các thành viên, có thể sử dụng thừa kế và có thể có hàm thành viên.
Tôi sẽ khuyên bạn nên sử dụng các cấu trúc như các cấu trúc dữ liệu cũ đơn giản mà không có bất kỳ tính năng nào giống như lớp và sử dụng các lớp làm cấu trúc dữ liệu tổng hợp với private
các hàm thành viên và dữ liệu.
Như mọi người khác lưu ý, thực sự chỉ có hai sự khác biệt về ngôn ngữ:
struct
mặc định truy cập công cộng và class
mặc định truy cập riêng.struct
mặc định là public
thừa kế và class
mặc định là private
thừa kế. (Trớ trêu thay, cũng như rất nhiều thứ trong C ++, mặc định là ngược: public
kế thừa là lựa chọn phổ biến hơn, nhưng mọi người hiếm khi tuyên bố struct
s chỉ để tiết kiệm khi gõ public
từ khóa "".Nhưng sự khác biệt thực tế trong thực tế là giữa a class
/ struct
khai báo hàm tạo / hàm hủy và một hàm không. Có một số đảm bảo nhất định đối với loại POD "dữ liệu cũ", không còn áp dụng khi bạn tiếp quản công trình của lớp. Để giữ sự khác biệt này rõ ràng, nhiều người cố tình chỉ sử dụng struct
s cho các loại POD và nếu họ sẽ thêm bất kỳ phương thức nào, hãy sử dụng class
es. Sự khác biệt giữa hai mảnh dưới đây là vô nghĩa:
class X
{
public:
// ...
};
struct X
{
// ...
};
(Ngẫu nhiên, đây là một chủ đề với một số giải thích tốt về "loại POD" thực sự có nghĩa là gì : Các loại POD trong C ++ là gì? )
struct
hay class
không có liên quan đến việc đối tượng của bạn là POD hay bạn nên xác định hàm tạo / hàm hủy sao chép. Các chức năng thành viên cũng không có liên quan đến một cái gì đó là POD. Khi tôi đọc lại những gì bạn đã viết, tôi thấy bạn không gợi ý gì khác, nhưng cách diễn đạt hiện tại thật khó hiểu
Có rất nhiều quan niệm sai lầm trong các câu trả lời hiện có.
Cả hai class
và struct
tuyên bố một lớp.
Có, bạn có thể phải sắp xếp lại các từ khóa sửa đổi truy cập của mình bên trong định nghĩa lớp, tùy thuộc vào từ khóa bạn đã sử dụng để khai báo lớp.
Nhưng, ngoài cú pháp, lý do duy nhất để chọn cái này là cái khác là quy ước / kiểu / sở thích.
Một số người thích gắn bó với struct
từ khóa cho các lớp không có hàm thành viên, vì định nghĩa kết quả "trông giống như" một cấu trúc đơn giản từ C.
Tương tự, một số người thích sử dụng class
từ khóa cho các lớp có chức năng và private
dữ liệu thành viên , vì nó nói "lớp" trên đó và do đó trông giống như các ví dụ từ cuốn sách yêu thích của họ về lập trình hướng đối tượng.
Thực tế là điều này hoàn toàn phụ thuộc vào bạn và nhóm của bạn, và nó sẽ thực sự không có gì khác biệt đối với chương trình của bạn.
Hai lớp sau đây hoàn toàn tương đương theo mọi cách trừ tên của chúng:
struct Foo
{
int x;
};
class Bar
{
public:
int x;
};
Bạn thậm chí có thể chuyển từ khóa khi khai báo lại:
class Foo;
struct Bar;
(mặc dù điều này phá vỡ các bản dựng Visual Studio do không tuân thủ, do đó trình biên dịch sẽ phát ra cảnh báo khi bạn thực hiện việc này.)
và các biểu thức sau đây đều đánh giá là đúng:
std::is_class<Foo>::value
std::is_class<Bar>::value
Tuy nhiên, xin lưu ý rằng bạn không thể chuyển từ khóa khi xác định lại ; điều này chỉ bởi vì (theo quy tắc một định nghĩa) các định nghĩa lớp trùng lặp giữa các đơn vị dịch phải "bao gồm cùng một chuỗi các mã thông báo" . Điều này có nghĩa bạn thậm chí không thể trao đổi const int member;
với int const member;
, và không có gì để làm với các ngữ nghĩa của class
hay struct
.
class foo { public: ... };
và một đơn vị dịch thuật khác có thể phải struct foo { ... };
giữ đúng theo yêu cầu "hoàn toàn tương đương". Lý do là các tuyên bố không đầy đủ struct foo;
và class foo;
có thể thay thế cho nhau. Chúng không chỉ định nội dung lớp và vì vậy chúng không nói gì đến bố cục truy cập.
Foo
và Bar
vẫn còn tương đương / loại giống hệt nhau. Tôi đã chắc chắn nói "khi khai báo lại " và đưa ra một ví dụ. Nghĩ về nó, tôi sẽ làm rõ điều này trong câu trả lời để đảm bảo rằng tôi không lừa dối mọi người vào UB
Lần duy nhất tôi sử dụng struct thay vì một lớp là khi khai báo functor ngay trước khi sử dụng nó trong một lệnh gọi hàm và muốn giảm thiểu cú pháp vì mục đích rõ ràng. ví dụ:
struct Compare { bool operator() { ... } };
std::sort(collection.begin(), collection.end(), Compare());
Từ C ++ FAQ Lite :
Các thành viên và các lớp cơ sở của một cấu trúc được công khai theo mặc định, trong khi trong lớp, chúng mặc định là riêng tư. Lưu ý: bạn nên làm cho các lớp cơ sở của mình rõ ràng công khai, riêng tư hoặc được bảo vệ, thay vì dựa vào các mặc định.
struct và class khác có chức năng tương đương.
OK, đủ nói chuyện kỹ thuật sạch sẽ khó chịu. Về mặt tình cảm, hầu hết các nhà phát triển tạo ra sự khác biệt mạnh mẽ giữa một lớp và một cấu trúc. Một cấu trúc chỉ đơn giản cảm thấy giống như một đống bit mở với rất ít cách thức đóng gói hoặc chức năng. Một lớp học cảm thấy như một thành viên sống và có trách nhiệm với xã hội với các dịch vụ thông minh, rào cản đóng gói mạnh mẽ và giao diện được xác định rõ. Vì đó là ý nghĩa mà hầu hết mọi người đã có, nên có lẽ bạn nên sử dụng từ khóa struct nếu bạn có một lớp có rất ít phương thức và có dữ liệu công khai (những thứ đó tồn tại trong các hệ thống được thiết kế tốt!), Nhưng nếu không thì có lẽ bạn nên sử dụng lớp từ khóa.
Một nơi mà một cấu trúc có ích cho tôi là khi tôi có một hệ thống nhận các tin nhắn định dạng cố định (nói chung là một cổng nối tiếp) từ một hệ thống khác. Bạn có thể truyền luồng byte thành một cấu trúc xác định các trường của bạn và sau đó dễ dàng truy cập vào các trường.
typedef struct
{
int messageId;
int messageCounter;
int messageData;
} tMessageType;
void processMessage(unsigned char *rawMessage)
{
tMessageType *messageFields = (tMessageType *)rawMessage;
printf("MessageId is %d\n", messageFields->messageId);
}
Rõ ràng, đây là điều tương tự bạn sẽ làm trong C, nhưng tôi thấy rằng chi phí chung của việc phải giải mã tin nhắn thành một lớp thường không đáng.
operator >>
trên một lớp thay vì viết processMessage
hàm, điều này sẽ làm cho C ++ của bạn trông giống C ++ hơn và giống như C.
__packed__
cấu trúc và có một triển khai ifdef nhận biết endian (bạn cần lật thứ tự trên một máy trong đó endianess đối diện với nguồn dữ liệu ngoài Đang cung cấp). Nó không đẹp, nhưng tôi đã sử dụng để đóng gói / giải nén các thanh ghi cho các thiết bị ngoại vi từ xa trên các nền tảng nhúng theo cách di động.
char
loại, được miễn trừ răng cưa. Tuy nhiên, vẫn còn một vấn đề, mặc dù có một vấn đề khác: Đúc một char*
loại khác, nếu thực sự không có bất kỳ đối tượng nào thuộc loại sau đã được khởi tạo tại địa chỉ đó, thì đó là UB vì nó vi phạm quy tắc trọn đời. Afaik, ngay cả khi loại đích có thể xây dựng tầm thường, chỉ cần có bộ nhớ được cấp phát là không đủ cho C ++ để chính thức cho phép coi bộ nhớ đó là loại đó.
Bạn có thể sử dụng "struct" trong C ++ nếu bạn đang viết thư viện có phần bên trong là C ++ nhưng API có thể được gọi bằng mã C hoặc C ++. Bạn chỉ cần tạo một tiêu đề duy nhất chứa các cấu trúc và các hàm API toàn cầu mà bạn hiển thị cho cả mã C và C ++ như sau:
// C access Header to a C++ library
#ifdef __cpp
extern "C" {
#endif
// Put your C struct's here
struct foo
{
...
};
// NOTE: the typedef is used because C does not automatically generate
// a typedef with the same name as a struct like C++.
typedef struct foo foo;
// Put your C API functions here
void bar(foo *fun);
#ifdef __cpp
}
#endif
Sau đó, bạn có thể viết một thanh chức năng () trong tệp C ++ bằng mã C ++ và làm cho nó có thể gọi được từ C và hai thế giới có thể chia sẻ dữ liệu thông qua các cấu trúc được khai báo. Tất nhiên có những cảnh báo khác khi trộn C và C ++ nhưng đây là một ví dụ đơn giản.
Như mọi người nói, sự khác biệt thực sự duy nhất là truy cập mặc định. Nhưng tôi đặc biệt sử dụng struct khi tôi không muốn bất kỳ kiểu đóng gói nào với một lớp dữ liệu đơn giản, ngay cả khi tôi thực hiện một số phương thức trợ giúp. Ví dụ, khi tôi cần một cái gì đó như thế này:
struct myvec {
int x;
int y;
int z;
int length() {return x+y+z;}
};
Để trả lời câu hỏi của riêng tôi (không biết xấu hổ), Như đã đề cập, đặc quyền truy cập là sự khác biệt duy nhất giữa chúng trong C ++.
Tôi có xu hướng chỉ sử dụng một cấu trúc để lưu trữ dữ liệu. Tôi sẽ cho phép nó có được một vài chức năng trợ giúp nếu nó làm việc với dữ liệu dễ dàng hơn. Tuy nhiên, ngay khi dữ liệu yêu cầu kiểm soát luồng (tức là getters / setters duy trì hoặc bảo vệ trạng thái bên trong) hoặc bắt đầu thực hiện bất kỳ chức năng chính nào (về cơ bản giống như đối tượng hơn), nó sẽ được 'nâng cấp' lên một lớp để có ý định giao tiếp tốt hơn.
Cấu trúc ( POD , nói chung hơn) rất tiện lợi khi bạn cung cấp giao diện tương thích C với triển khai C ++, vì chúng có thể di chuyển qua biên giới ngôn ngữ và các định dạng liên kết.
Nếu điều đó không liên quan đến bạn, thì tôi cho rằng việc sử dụng "struct" thay vì "class" là một người truyền đạt ý định tốt (như @ZeroSignal đã nói ở trên). Structs cũng có ngữ nghĩa sao chép dễ dự đoán hơn, vì vậy chúng hữu ích cho dữ liệu bạn định ghi vào phương tiện bên ngoài hoặc gửi qua dây.
Các cấu trúc cũng tiện dụng cho các tác vụ siêu lập trình khác nhau, như các mẫu đặc điểm chỉ phơi bày một loạt các typedefs phụ thuộc:
template <typename T> struct type_traits {
typedef T type;
typedef T::iterator_type iterator_type;
...
};
... Nhưng đó thực sự chỉ là lợi dụng mức độ bảo vệ mặc định của struct là công khai ...
Đối với C ++, thực sự không có nhiều sự khác biệt giữa các cấu trúc và các lớp. Sự khác biệt về chức năng chính là các thành viên của một cấu trúc được công khai theo mặc định, trong khi chúng là riêng tư theo mặc định trong các lớp. Mặt khác, theo như ngôn ngữ có liên quan, chúng là tương đương.
Điều đó nói rằng, tôi có xu hướng sử dụng các cấu trúc trong C ++ giống như tôi làm trong C #, tương tự như những gì Brian đã nói. Structs là các thùng chứa dữ liệu đơn giản, trong khi các lớp được sử dụng cho các đối tượng cần hành động trên dữ liệu ngoài việc chỉ giữ nó.
Họ là khá nhiều điều tương tự. Nhờ vào phép thuật của C ++, một cấu trúc có thể giữ các hàm, sử dụng tính kế thừa, được tạo bằng cách sử dụng "mới" và cứ như vậy giống như một lớp
Sự khác biệt duy nhất về chức năng là một lớp bắt đầu bằng quyền truy cập riêng, trong khi cấu trúc bắt đầu bằng công khai. Đây là khả năng tương thích ngược với C.
Trong thực tế, tôi luôn sử dụng các cấu trúc như các chủ sở hữu dữ liệu và các lớp làm đối tượng.
Như những người khác đã chỉ ra
Có một khuyến nghị rõ ràng về thời điểm sử dụng từ Stroustrup / Sutter:
Sử dụng lớp nếu lớp có bất biến; sử dụng struct nếu các thành viên dữ liệu có thể thay đổi độc lập
Tuy nhiên, hãy nhớ rằng không phải là khôn ngoan để chuyển tiếp tuyên bố sth. như một lớp ( class X;
) và định nghĩa nó là struct ( struct X { ... }
). Nó có thể hoạt động trên một số trình liên kết (ví dụ: g ++) và có thể thất bại với những người khác (ví dụ: MSVC), vì vậy bạn sẽ thấy mình trong địa ngục của nhà phát triển.
class Foo; struct Foo { void bar() {} }; int main() { Foo().bar(); }
không chỉ biên dịch và chạy với MSVC 2017, nó thậm chí còn tạo ra một cảnh báo rõ ràng Foo
được tuyên bố là struct
nhưng được định nghĩa là class
. Nhưng tôi cũng nhớ rõ rằng phải mất nửa ngày để tìm ra con bọ ngu ngốc đó. Tôi không chắc chắn phiên bản MSVC nào chúng tôi đã sử dụng trước đó.
class
hay struct
khai báo chuyển tiếp và cả hai có thể thay thế tự do theo tiêu chuẩn (mặc dù người ta biết rằng VS cảnh báo; tôi luôn cho rằng đó chỉ là để tránh những lỗi lập trình rõ ràng). Một cái gì đó không có mùi ngay tại đây. Bạn có chắc chắn đó không phải là lỗi vi phạm ODR?
struct
trước đến sau class
, các vấn đề sẽ biến mất. Đến hôm nay, tôi cũng thấy lạ. Tôi rất vui nếu bạn có thể làm sáng tỏ nó.
Các thành viên lớp là mặc định.
class test_one {
int main_one();
};
Tương đương với
class test_one {
private:
int main_one();
};
Vì vậy, nếu bạn cố gắng
int two = one.main_one();
Chúng tôi sẽ nhận được một lỗi: main_one is private
bởi vì nó không thể truy cập. Chúng ta có thể giải quyết nó bằng cách khởi tạo nó bằng cách chỉ định công khai tức là
class test_one {
public:
int main_one();
};
Một struct là một lớp nơi các thành viên được công khai theo mặc định.
struct test_one {
int main_one;
};
Có nghĩa main_one
là riêng tư tức là
class test_one {
public:
int main_one;
};
Tôi sử dụng các cấu trúc cho các cấu trúc dữ liệu trong đó các thành viên có thể nhận bất kỳ giá trị nào, cách đó dễ dàng hơn.
Một lợi thế của struct
trên class
là nó tiết kiệm một dòng mã, nếu tôn trọng "các thành viên công khai đầu tiên, sau đó tin". Trong ánh sáng này, tôi thấy từ khóa class
vô dụng.
Đây là một lý do khác để chỉ sử dụng struct
và không bao giờ class
. Một số nguyên tắc kiểu mã cho C ++ đề xuất sử dụng các chữ cái nhỏ cho macro chức năng, lý do là khi macro được chuyển đổi thành hàm nội tuyến, không nên thay đổi tên. Tương tự ở đây. Bạn có cấu trúc kiểu C đẹp và một ngày nào đó, bạn phát hiện ra rằng bạn cần thêm một hàm tạo, hoặc một số phương thức tiện lợi. Bạn có thay đổi nó thành một class
? Mọi nơi?
Phân biệt giữa struct
s và class
es chỉ là quá nhiều rắc rối, đi vào cách làm những gì chúng ta nên làm - lập trình. Giống như rất nhiều vấn đề của C ++, nó nảy sinh từ mong muốn mạnh mẽ về khả năng tương thích ngược.
class
? Bạn có nghĩ rằng một lớp được xác định bằng struct
từ khóa không thể có các hàm thành viên hoặc hàm tạo không?
joe()
phải được xác định với class
từ khóa? Mỗi lớp có ít nhất 4 int
thành viên phải được xác định bằng struct
từ khóa?
struct
, tập hợp với các phương thức được định nghĩa bằng class
". Quá nhiều rắc rối.
chúng giống nhau với các mặc định khác nhau (mặc định là riêng tư và mặc định là class
công khai struct
), vì vậy về mặt lý thuyết chúng hoàn toàn có thể hoán đổi cho nhau.
vì vậy, nếu tôi chỉ muốn gói một số thông tin để di chuyển, tôi sử dụng một cấu trúc, ngay cả khi tôi đặt một vài phương thức ở đó (nhưng không nhiều). Nếu đó là một thứ không rõ ràng, trong đó việc sử dụng chính sẽ thông qua các phương thức và không trực tiếp đến các thành viên dữ liệu, tôi sử dụng một lớp đầy đủ.
Các cấu trúc theo mặc định có quyền truy cập công khai và các lớp theo mặc định có quyền truy cập riêng.
Cá nhân tôi sử dụng các cấu trúc cho các đối tượng truyền dữ liệu hoặc làm đối tượng giá trị. Khi được sử dụng như vậy tôi khai báo tất cả các thành viên là const để ngăn sửa đổi bởi mã khác.
Cả hai struct
và class
đều giống nhau dưới mui xe mặc dù với các mặc định khác nhau về khả năng hiển thị, struct
mặc định là công khai và class
mặc định là riêng tư. Bạn có thể thay đổi cái này thành cái khác với cách sử dụng private
và public
. Cả hai đều cho phép kế thừa, phương thức, hàm tạo, hàm hủy và tất cả các tính năng còn lại của ngôn ngữ hướng đối tượng.
Tuy nhiên, một điểm khác biệt lớn giữa hai loại đó struct
là từ khóa được hỗ trợ trong C trong khi đó class
thì không. Điều này có nghĩa là người ta có thể sử dụng một struct
tệp bao gồm có thể #include
vào C ++ hoặc C miễn struct
là kiểu C đơn giản struct
và mọi thứ khác trong tệp đính kèm đều tương thích với C, tức là không có từ khóa cụ thể C ++ nào private
, như public
, không phương pháp, không kế thừa, v.v.
Kiểu AC struct
có thể được sử dụng với các giao diện khác hỗ trợ sử dụng kiểu C struct
để truyền dữ liệu qua lại trên giao diện.
Phong cách AC struct
là một loại mẫu (không phải mẫu C ++ mà là mẫu hoặc khuôn tô) mô tả bố cục của vùng nhớ. Trong những năm qua các giao diện sử dụng được từ C và C với plug-ins (ở đây đang nhìn vào bạn Java và Python và Visual Basic) đã được tạo ra một số trong đó làm việc với C phong cách struct
.
Về mặt kỹ thuật cả hai đều giống nhau trong C ++ - ví dụ, một cấu trúc có thể có các toán tử quá tải, v.v.
Tuy nhiên :
Tôi sử dụng các cấu trúc khi tôi muốn truyền thông tin của nhiều loại đồng thời Tôi sử dụng các lớp khi tôi đang xử lý một đối tượng "chức năng".
Hy vọng nó giúp.
#include <string>
#include <map>
using namespace std;
struct student
{
int age;
string name;
map<string, int> grades
};
class ClassRoom
{
typedef map<string, student> student_map;
public :
student getStudentByName(string name) const
{ student_map::const_iterator m_it = students.find(name); return m_it->second; }
private :
student_map students;
};
Chẳng hạn, tôi đang trả lại một sinh viên theo cấu trúc trong các phương thức get ... () ở đây - thưởng thức.
Khi nào bạn sẽ chọn sử dụng struct và khi nào sử dụng lớp trong C ++?
Tôi sử dụng struct
khi tôi xác định functors
và POD
. Nếu không thì tôi dùng class
.
// '()' is public by default!
struct mycompare : public std::binary_function<int, int, bool>
{
bool operator()(int first, int second)
{ return first < second; }
};
class mycompare : public std::binary_function<int, int, bool>
{
public:
bool operator()(int first, int second)
{ return first < second; }
};
std::binary_function<>
không chỉ bị phản đối, c ++ 17 thậm chí còn loại bỏ nó.
Tất cả các thành viên lớp là riêng tư theo mặc định và tất cả các thành viên cấu trúc được công khai theo mặc định. Lớp có các cơ sở riêng mặc định và Struct có các cơ sở công cộng mặc định. Struct trong trường hợp C không thể có các hàm thành viên trong trường hợp của C ++, chúng ta có thể có các hàm thành viên được thêm vào struct. Ngoài những khác biệt này, tôi không tìm thấy bất cứ điều gì đáng ngạc nhiên về chúng.
Tôi chỉ sử dụng struct khi tôi cần giữ một số dữ liệu mà không có bất kỳ chức năng thành viên nào liên quan đến nó (để hoạt động trên dữ liệu thành viên) và để truy cập trực tiếp vào các biến dữ liệu.
Ví dụ: Đọc / ghi dữ liệu từ các tệp và luồng ổ cắm, v.v. Truyền các đối số hàm trong một cấu trúc trong đó các đối số hàm quá nhiều và cú pháp hàm trông quá dài.
Về mặt kỹ thuật, không có sự khác biệt lớn giữa lớp và cấu trúc ngoại trừ khả năng truy cập mặc định. Hơn nữa nó phụ thuộc vào phong cách lập trình cách bạn sử dụng nó.
Tôi nghĩ rằng Structs được dự định là một Cấu trúc dữ liệu (giống như một mảng thông tin loại đa dữ liệu) và các lớp được đặt cho Mã đóng gói (như các bộ sưu tập các chương trình con & hàm) ..
:
Tôi không bao giờ sử dụng "struct" trong C ++.
Tôi không bao giờ có thể tưởng tượng một kịch bản mà bạn sẽ sử dụng một cấu trúc khi bạn muốn các thành viên riêng tư, trừ khi bạn cố tình gây nhầm lẫn.
Có vẻ như việc sử dụng các cấu trúc là một chỉ dẫn cú pháp về cách sử dụng dữ liệu, nhưng tôi chỉ muốn tạo một lớp và cố gắng làm cho nó rõ ràng trong tên của lớp hoặc thông qua các nhận xét.
Ví dụ
class PublicInputData {
//data members
};
struct
Theo mặc định, sẽ không tuyên bố rằng các thành viên của lớp sẽ được công khai?