2011-10-20 32 views
11

Nếu bạn muốn đặt các định nghĩa hàm trong file header, nó xuất hiện có ba giải pháp khác nhau:đặt định nghĩa hàm trong file header

  1. đánh dấu chức năng như inline
  2. đánh dấu chức năng như static
  3. đặt hàm vào một không gian tên ẩn danh

(Cho đến gần đây, tôi thậm chí không biết # 1.) Vậy sự khác biệt với các giải pháp này là gì và khi nào tôi Tôi thích cái nào? Tôi đang ở trong thế giới chỉ tiêu đề, vì vậy tôi thực sự cần các định nghĩa trong các tệp tiêu đề.

+8

Bạn quên: Biến chúng thành các mẫu chức năng. Đó là những gì tôi thường thích. – sbi

+1

không sử dụng tĩnh dẫn đến nhiều bản sao khác nhau và sự điên rồ. –

+2

Giải pháp "một bản sao trong mỗi không gian tên vô danh" dẫn đến cùng một sự điên rồ. – MSalters

Trả lời

11

static và các phiên bản không tên tên cuối cùng là giống nhau: mỗi Đơn vị dịch sẽ chứa phiên bản riêng của hàm đó, và điều đó có nghĩa là có một hàm tĩnh f, con trỏ &f sẽ khác nhau trong mỗi đơn vị dịch và chương trình sẽ chứa N các phiên bản khác nhau của f (mã khác trong mã nhị phân).

Đây là không cách tiếp cận đúng để cung cấp một chức năng trong một tiêu đề, nó sẽ cung cấp N (chính xác bằng) chức năng khác nhau. Nếu hàm chứa static người dân địa phương sau đó sẽ có N khác nhau static biến địa phương ...

EDIT: Để làm điều này rõ ràng hơn: nếu những gì bạn muốn là để cung cấp các định nghĩa của một hàm trong một tiêu đề mà không phá vỡ quy tắc một định nghĩa, cách tiếp cận đúng là tạo hàm inline.

+0

Vì vậy, 'inline' là cách tiếp cận đúng? Sẽ thật tuyệt nếu bạn làm điều đó rõ ràng. – fredoverflow

+0

Sự hiểu biết của tôi về điều này là tương tự và tôi đăng giống như một câu trả lời nhưng sau đó tôi đã xóa nó, Vì tôi đã mắc kẹt với Q, 'Làm thế nào để một hàm được định nghĩa trong tiêu đề là nội tuyến, làm cho nó bỏ qua ODR?', Tôi nghĩ' Mục $ 3.2/5' địa chỉ này nhưng tôi không chắc chắn. Đây có lẽ là chi tiết hơn so với tìm kiếm trong Q nhưng bạn có thể xin vui lòng ellaborate về điều này. –

+0

@Als: 3.2/3 * Mỗi chương trình phải chứa chính xác một định nghĩa của mọi hàm hoặc đối tượng không phải nội tuyến được sử dụng trong chương trình đó; không cần chẩn đoán. [...] Một hàm nội tuyến sẽ được định nghĩa trong mọi đơn vị dịch mà nó được sử dụng. * (Từ ngữ từ C++ 03, nhưng cùng có thể được tìm thấy trong C++ 11 trong đó * sử dụng * là * ODR-được sử dụng *) –

0

static chức năng (tương đương với không gian tên ẩn danh) nhận các bản sao khác nhau cho mỗi TU. Nếu hàm này là entrant thì về cơ bản là giống hệt nhau (một số trình biên dịch có thể có sự khác biệt ở mức assembly) nhưng nếu không thì nó sẽ có dữ liệu tĩnh khác nhau cho mỗi TU. Các hàm nội tuyến được xếp - nghĩa là chúng chỉ có một bản sao của dữ liệu tĩnh cho mỗi TU.

+1

@TonyK: Trong khi tôi đồng ý với đề xuất không sử dụng các chữ viết tắt và sử dụng ký hiệu đầy đủ, tôi không đồng ý với 'OP rõ ràng không phải là chuyên gia'. OP là một trong số ít các chuyên gia trong SO thực sự hiểu C++ cốt lõi. –

+2

Vâng, tôi đã quyết định xóa bình luận của mình, nhưng đã quá muộn ... Vì vậy, hãy để tôi đặt lại ở đây: Sử dụng chữ viết tắt như TU giả định mức độ kinh nghiệm trong trình đọc của bạn làm cho lời giải thích của bạn không cần thiết. (Trừ khi, rõ ràng, người đọc của bạn là FredOverflow.) Và BTW, nó có nghĩa là Đơn vị dịch thuật. – TonyK

4

Theo như tôi biết, chỉ có inline và chức năng mẫu có thể được xác định trong tệp tiêu đề. Các hàm

static không được dùng nữa và các hàm được xác định trong không gian tên chưa đặt tên sẽ được sử dụng thay thế (xem 7.3.1.1 p2). Khi bạn định nghĩa một hàm trong một không gian tên chưa đặt tên trong một tiêu đề, thì mọi mã nguồn bao gồm tiêu đề đó (trực tiếp hoặc gián tiếp) sẽ có một định nghĩa duy nhất (xem 7.3.1.1 p1). Do đó, các hàm không nên được định nghĩa trong không gian tên chưa đặt tên trong các tệp tiêu đề (chỉ trong các tệp nguồn).

Tiêu chuẩn được tham chiếu đến từ tiêu chuẩn C++ 03.

EDIT:

dụ Tiếp theo cho thấy lý do tại sao chức năng và các biến không cần được xác định vào không gian tên vô danh trong tiêu đề:

ops.hpp chứa:

#ifndef OPS_HPP 
#define OPS_HPP 
namespace 
{ 
int a; 
} 
#endif 

DK1 .hpp chứa:

#ifndef DK1_HPP 
#define DK1_HPP 
void setValue(); 
void printValue(); 
#endif 

dk1.cpp chứa:

#include "dk1.hpp" 
#include "ops.hpp" 
#include <iostream> 

void setValue() 
{ 
    a=5; 
} 
void printValue() 
{ 
    std::cout<<a<<std::endl; 
} 

dk.cpp chứa:

#include "dk1.hpp" 
#include "ops.hpp" 
#include <iostream> 

int main() 
{ 
    // set and print a 
    setValue(); 
    printValue(); 

    // set and print it again 
    a = 22; 
    std::cout<<a<<std::endl; 

    // print it again 
    printValue(); 
} 

Compile như thế này:

g++ -ansi -pedantic -Wall -Wextra dk.cpp dk1.cpp 

và đầu ra:

5 
22 
5 

ops biến a là khác nhau cho các nguồn tập tin dk1.cppdk.cpp

+0

Không có gì sai khi có các không gian tên vô danh với các định nghĩa hàm trong các tiêu đề - không vi phạm các hàm ODR – Flexo

+0

'static' không bao giờ bị phản đối, chỉ có các đối tượng' tĩnh' (trước C++ 11). –

+1

@awoodland: Không có gì vốn đã sai từ quan điểm của trình biên dịch, nhưng hầu hết có lẽ là từ quan điểm của chương trình. Có vẻ như ** một hàm ** trong tiêu đề thực sự là ** nhiều ** chức năng trong các đơn vị dịch khác nhau, nó sẽ tạo thêm mã (nhị phân lớn hơn, hiệu suất kém hơn của bộ nhớ cache hướng dẫn), và nếu hàm chứa * local static * biến, mỗi đơn vị dịch sẽ đề cập đến phiên bản riêng của nó. Trình biên dịch sẽ làm điều đó và hạnh phúc. Nhưng bất cứ ai cần phải gỡ lỗi đó trong tương lai sẽ không được hạnh phúc như vậy. –

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