Phải làm gì nếu tôi ghét các tệp tiêu đề C ++?


25

Tôi luôn luôn bối rối về các tập tin tiêu đề. Chúng rất lạ: bạn bao gồm tệp .h không bao gồm .cpp nhưng .cpp cũng được biên dịch theo cách nào đó.

Gần đây tôi đã tham gia một dự án nhóm, và tất nhiên, cả .h và .cpp đều được sử dụng.
Tôi hiểu rằng điều này rất quan trọng, nhưng tôi không thể sống với việc sao chép mọi khai báo hàm trong mỗi lớp chúng ta có.

Làm cách nào để xử lý quy ước 2 tệp một cách hiệu quả?
Có công cụ nào để giúp với điều đó không, hoặc tự động thay đổi một tệp giống như ví dụ bên dưới thành .h và .cpp? (cụ thể cho MS VC ++ 2010)

class A
{
...
    Type f(Type a,Type b)
    {
        //implementation here, not in another file!
    }
...
};

Type f(Type a)
{
     //implementation here
}
...

8
Câu hỏi này có thể đi một vài cách .. "Tại sao chúng ta cần tiêu đề khi sử dụng c ++" hoặc "Bạn có nghĩ rằng một ngôn ngữ hiện đại có nghĩa là được biên dịch nên sử dụng tiêu đề?" Như nó là, nó có 'Tôi phải làm gì "và" ghét "trong tiêu đề, đặt ra rất nhiều cờ.
Tim Post

4
Câu hỏi của bạn làm cho có vẻ như bạn không hiểu C ++ hoặc bất kỳ hệ thống nào bạn sử dụng biên dịch nó. Học cách sử dụng nó đúng cách, và sau đó đặt câu hỏi chủ quan hơn.
David Thornley

31
Câu đầu tiên của bạn chỉ ra rằng bạn không "hiểu mọi thứ về tiêu đề". Bao gồm tệp .h không làm cho tệp .cpp tương ứng bị "biên dịch theo cách nào đó". Bạn biên dịch các tệp .cpp một cách độc lập theo quyền riêng của họ. Nếu bạn chưa biên dịch .cpp tương ứng, thì việc bao gồm một tiêu đề không có tệp đối tượng tương ứng sẽ khiến trình liên kết bị lỗi.
Paul Butcher

5
Phải làm sao Tìm một ngôn ngữ khác nếu nó làm phiền bạn nhiều như vậy.
Paul Nathan

5
Về "không thể sống với dán sao chép": Bất cứ khi nào một người cập nhật một chức năng, người ta phải cập nhật tất cả những nơi mà nó được gọi bằng mọi cách. Vì người gọi khó tìm hơn nhiều so với khai báo trong tệp tiêu đề, cập nhật tiêu đề chỉ là một chi tiết nhỏ.
Sjoerd

Câu trả lời:


15

Viết thêm Tái cấu trúc C ++ thân thiện

Trong C ++, bạn hoàn toàn không phải sử dụng các tiêu đề. Bạn có thể định nghĩa toàn bộ đối tượng trong một tệp giống như với C # hoặc Java. Các nhà phát triển C thường sẽ chỉ giữ các cuộc gọi bên ngoài trong một tệp tiêu đề. Tất cả các cuộc gọi nội bộ sẽ được xác định trong tệp .c. Với cùng một mã thông báo, bạn có thể dự trữ các tệp C ++ .h của mình cho các lớp / giao diện (các lớp trừu tượng ảo thuần túy) / vv. được dự định chia sẻ bên ngoài DLL. Đối với các lớp / cấu trúc / giao diện nội bộ, v.v. bạn chỉ cần bao gồm tệp .cpp bạn cần:

#include<myclass.cpp>

Đây dường như không phải là cách tiếp cận phổ biến nhất, nhưng đó là C ++ hợp pháp. Nó chắc chắn sẽ là một khả năng cho tất cả các mã nội bộ của bạn. Điều này cho phép mã nội bộ và tập hợp các lớp thay đổi hoàn toàn hơn rất nhiều trong khi cung cấp giao diện ổn định hơn cho mã bên ngoài thư viện / tệp thực thi của bạn để tương tác.

Có cả lớp của bạn trong một tệp sẽ giúp bạn dễ dàng thực hiện những gì bạn muốn. Nó sẽ không giải quyết vấn đề đổi tên một phương thức và phải tìm kiếm mọi nơi mà phương thức đó được gọi, nhưng nó sẽ đảm bảo bạn có các thông báo lỗi dễ hiểu hơn. Không có gì tệ hơn việc tiêu đề của bạn khai báo một phương thức theo một cách, nhưng bạn thực hiện nó theo cách khác. Mã khác gọi tệp tiêu đề sẽ biên dịch đúng và bạn sẽ nhận được ngoại lệ liên kết, trong khi tệp triển khai sẽ là mã phàn nàn rằng phương thức không được xác định. Khi bạn xác định mọi phương thức tại chỗ (trong khai báo lớp thực tế), bạn sẽ nhận được thông báo lỗi tương tự cho dù tệp nào có chứa nó.

Bạn cũng có thể muốn xem xét câu hỏi này: Các công cụ tái cấu trúc tốt cho C ++

Làm thế nào C / C ++ giải quyết các tệp tiêu đề / thực hiện

Ở cấp độ C cơ sở (và C ++ được xây dựng trên nền tảng đó), các tệp tiêu đề khai báo lời hứa của hàm / struct / biến đủ để cho phép trình biên dịch tạo tệp đối tượng. Tương tự các tệp tiêu đề C ++ khai báo lời hứa của các hàm, cấu trúc, lớp, v.v ... Đây là định nghĩa mà trình biên dịch sử dụng để dự trữ không gian trong ngăn xếp, v.v.

Các tập tin .c hoặc .cpp có triển khai. Khi trình biên dịch chuyển đổi từng tệp thực hiện thành một tệp đối tượng, có các móc nối với các khái niệm chưa được thực hiện (những gì đã được khai báo trong tiêu đề). Trình liên kết liên kết các hook với các cài đặt trong các tệp đối tượng khác và tạo ra một nhị phân lớn hơn bao gồm tất cả các mã (thư viện dùng chung hoặc tệp thực thi).

Cụ thể VS

Khi làm việc với những người trong Visual Studio, có một số trình hướng dẫn giúp mọi thứ dễ dàng hơn một chút. Trình hướng dẫn lớp mới sẽ tạo cặp tệp thực hiện và tiêu đề phù hợp của bạn. Thậm chí còn có một tính năng trình duyệt lớp sẽ cho phép bạn khai báo các phương thức mới. Nó sẽ đưa định nghĩa vào tiêu đề và cuống triển khai trong tệp .cpp. Visual Studio đã có những tính năng đó trong hơn một thập kỷ (miễn là tôi đã sử dụng chúng).


Vấn đề là, tôi luôn sửa đổi các lớp mọi lúc, không chỉ thêm các chức năng mới, v.v.
Oleh Prypin

5
@BlaXpirit: Vậy, tại sao bạn luôn sửa đổi rất nhiều lớp? Một trong những ý tưởng đằng sau thiết kế OO là có rất nhiều khối xây dựng khá ổn định. Nếu tôi sửa đổi nhiều lớp, tôi muốn có một ngôn ngữ năng động hơn, như Common Lisp hoặc Python.
David Thornley

2
Đó là những gì tôi đang làm. Tôi đang cải thiện / sửa đổi "các khối xây dựng" và thêm các khối mới
Oleh Prypin

C ++ chưa bao giờ được tái cấu trúc thân thiện. Khái niệm tái cấu trúc đã không đạt được động lực cho đến khi có các công cụ giúp thực hiện dễ dàng trong các IDE Java. LƯU Ý: các tính năng này đã có cho các nhà phát triển Smalltalk và các ngôn ngữ khác, nhưng nó không trở thành xu hướng cho đến khi nó có sẵn cho nhiều người. Cho đến nay tôi vẫn chưa thấy ai đó thực hiện điều đó một cách thông minh cho C ++. Có lẽ Resharper từ JetBrains? Tôi biết nó có mã C # và VB, nhưng tôi không chắc liệu nó có cung cấp cho bạn cấu trúc lại C ++ không.
Berin Loritsch

@Berin: Tôi đã tìm kiếm các công cụ tái cấu trúc C ++ một hoặc hai năm trước và tìm thấy hai điều. Chúng có giá khá cao vào thời điểm đó và tôi không thấy các phiên bản dùng thử, vì vậy tôi không biết họ đã làm gì. Hơn nữa, một người chỉ làm việc với emacs, điều này sẽ hạn chế hiệu quả của nó trong một cửa hàng Visual Studio.
David Thornley

13

Trở thành một nhà phát triển Java.

Nếu bạn thực sự phải tiếp tục phát triển trong C ++, bạn có thể thử sử dụng IDE. Thường thì họ cung cấp một số cơ chế để bạn có thể thêm một phương thức vào một lớp và nó tự động đặt khai báo trong tệp .h và định nghĩa trong tệp .cpp.


2
kthx, tôi phần nào biết Java, nhưng bạn không thể tạo DLL Win32 cấp thấp bằng nó, bạn có thể không?
Oleh Prypin

41
Tôi không biết tại sao, nhưng 'Trở thành nhà phát triển Java' bằng cách nào đó nghe có vẻ xúc phạm: D.
Oliver Weiler

2
Nếu bạn muốn làm trình độ thấp, hãy quên mọi thứ về 'ngôn ngữ dễ dàng'. Mức độ thấp chi phí mồ hôi và nước mắt.
Batibix

5
Không phải là một câu trả lời đặc biệt hữu ích.
ChrisF

1
@Oliver Weiler Tôi không coi "trở thành nhà phát triển Java" là một sự xúc phạm. Tôi lập trình cả bằng C ++ và Java, nhưng sở thích của tôi cho đến nay là Java vì việc ngồi xuống và viết mã hoạt động dễ dàng hơn (và dễ mang theo hơn). Nếu vì một lý do nào đó, bạn ghét sự tồn tại của các tệp tiêu đề, thử Java có thể là lựa chọn đúng (mặc dù thật lạ khi bạn ghét các tệp tiêu đề; tôi sẽ xem xét thay đổi trong IDE).
Trixie Wolf


4

Khi bạn viết những dòng đầu tiên của một lớp mới, thường là vì bạn chỉ cần nó ở một nơi duy nhất tại thời điểm đó. Sau đó, nó có thể được sử dụng ở nhiều nơi hơn, nhưng ban đầu nó thường không được sử dụng.

Nhiều lớp học của tôi bắt đầu ở đầu tệp .cpp hiện tại. Khi nó đã đủ ổn định để sử dụng nó ở nhiều nơi, tôi cắt-dán nó vào một tiêu đề. Mặc dù thường thì lớp biến mất nhanh như nó xuất hiện.


-1

Như một đề xuất để giúp xử lý các tệp tiêu đề C ++, thường sử dụng chúng mà không có phần mở rộng tệp hoặc hậu tố tệp, chẳng hạn như các thư viện "GCC".

Nếu đây là trường hợp của bạn, tôi khuyên bạn nên sử dụng phần mở rộng tệp " .hpp" (hoặc không dùng " .hxx") hoặc hậu tố tệp.

Bạn có thể phải định cấu hình trình biên dịch, môi trường dành cho nhà phát triển hoặc chương trình Được xây dựng.


3
Bạn đang nói về làm thế nào khi bạn bao gồm một tập tin như thế #include <iostream>nào? Những thứ đó không chỉ dành cho thư viện GCC. Trong thực tế, nó được định nghĩa trong tiêu chuẩn C ++ năm 1997 , phần 17.3.1.2. Tôi sẽ tránh đặt tên tập tin như vậy. Bạn có thể, nhưng lý do thư viện chuẩn C ++ đã làm điều đó có lẽ là để tránh xung đột đặt tên. Tôi thực sự thấy nó thực sự kỳ lạ khi trình biên dịch tự động thêm '.h' khi bạn bao gồm một tiêu đề, nó có vẻ khá không chuẩn đối với tôi. Và tôi không bao giờ thấy bất kỳ ai đặt tên tiêu đề mà không có hậu tố ngoại trừ thư viện chuẩn c ++.
vedoity

1
Ngoài ra, tôi nên lưu ý, tất cả các trình biên dịch mà tôi đã sử dụng, ngoại trừ borland (mà tôi rất ghét), không tự động thêm '.h' hoặc '.hpp' hoặc '.hxx' khi bạn thử để bao gồm một tập tin không có hậu tố. Đừng mong đợi #include <someclass>được đọc như #include <someclass.hpp>trên tất cả các trình biên dịch. Mã của bạn sẽ bị hỏng.
vedoity
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.