Tách các lớp C ++ được tạo khuôn mẫu thành các tệp .hpp / .cpp - có thể không?


96

Tôi gặp lỗi khi cố biên dịch lớp mẫu C ++ được phân tách giữa tệp .hpp.cpptệp:

$ g++ -c -o main.o main.cpp  
$ g++ -c -o stack.o stack.cpp   
$ g++ -o main main.o stack.o  
main.o: In function `main':  
main.cpp:(.text+0xe): undefined reference to 'stack<int>::stack()'  
main.cpp:(.text+0x1c): undefined reference to 'stack<int>::~stack()'  
collect2: ld returned 1 exit status  
make: *** [program] Error 1  

Đây là mã của tôi:

stack.hpp :

#ifndef _STACK_HPP
#define _STACK_HPP

template <typename Type>
class stack {
    public:
            stack();
            ~stack();
};
#endif

stack.cpp :

#include <iostream>
#include "stack.hpp"

template <typename Type> stack<Type>::stack() {
        std::cerr << "Hello, stack " << this << "!" << std::endl;
}

template <typename Type> stack<Type>::~stack() {
        std::cerr << "Goodbye, stack " << this << "." << std::endl;
}

main.cpp :

#include "stack.hpp"

int main() {
    stack<int> s;

    return 0;
}

ldtất nhiên là đúng: các ký hiệu không ở trong stack.o.

Câu trả lời cho câu hỏi này không giúp ích được gì, vì tôi đã làm như nó nói.
Điều này có thể hữu ích, nhưng tôi không muốn chuyển từng phương thức vào .hpptệp — tôi không cần phải làm vậy, phải không?

Có phải giải pháp hợp lý duy nhất để di chuyển mọi thứ trong .cpptệp vào .hpptệp và chỉ cần bao gồm mọi thứ, thay vì liên kết dưới dạng tệp đối tượng độc lập? Điều đó có vẻ xấu kinh khủng ! Trong trường hợp đó, tôi cũng có thể trở lại trạng thái trước đó của mình và đổi tên stack.cppthành stack.hppvà hoàn tất với nó.


Có hai cách giải quyết tuyệt vời khi bạn muốn thực sự ẩn mã của mình (trong tệp nhị phân) hoặc giữ cho mã sạch. Nó là cần thiết để giảm tính tổng quát mặc dù trong tình huống đầu tiên. Nó được giải thích ở đây: stackoverflow.com/questions/495021/…
Sheric

Câu trả lời:


151

Không thể viết việc triển khai lớp mẫu trong tệp cpp riêng biệt và biên dịch. Tất cả các cách để làm như vậy, nếu ai đó tuyên bố, là cách giải quyết để bắt chước việc sử dụng tệp cpp riêng biệt nhưng thực tế nếu bạn định viết thư viện lớp mẫu và phân phối nó với các tệp tiêu đề và lib để ẩn việc triển khai, thì điều đó đơn giản là không thể .

Để biết tại sao, chúng ta hãy xem xét quá trình biên dịch. Các tệp tiêu đề không bao giờ được biên dịch. Chúng chỉ được xử lý trước. Sau đó, mã được xử lý trước sẽ được ghép nối với tệp cpp được biên dịch thực sự. Bây giờ nếu trình biên dịch phải tạo bố cục bộ nhớ thích hợp cho đối tượng, nó cần biết kiểu dữ liệu của lớp mẫu.

Trên thực tế, phải hiểu rằng lớp mẫu hoàn toàn không phải là một lớp mà là một khuôn mẫu cho một lớp, khai báo và định nghĩa của lớp này được tạo bởi trình biên dịch tại thời điểm biên dịch sau khi lấy thông tin của kiểu dữ liệu từ đối số. Miễn là không thể tạo bố cục bộ nhớ, thì không thể tạo hướng dẫn định nghĩa phương thức. Hãy nhớ rằng đối số đầu tiên của phương thức lớp là toán tử 'this'. Tất cả các phương thức của lớp được chuyển đổi thành các phương thức riêng lẻ với tên mangling và tham số đầu tiên là đối tượng mà nó hoạt động. Đối số 'this' thực sự cho biết về kích thước của đối tượng mà trong đó lớp mẫu không có sẵn cho trình biên dịch trừ khi người dùng khởi tạo đối tượng bằng đối số kiểu hợp lệ. Trong trường hợp này nếu bạn đặt các định nghĩa phương thức trong một tệp cpp riêng biệt và cố gắng biên dịch nó, bản thân tệp đối tượng sẽ không được tạo với thông tin lớp. Quá trình biên dịch sẽ không thất bại, nó sẽ tạo tệp đối tượng nhưng sẽ không tạo bất kỳ mã nào cho lớp mẫu trong tệp đối tượng. Đây là lý do tại sao trình liên kết không thể tìm thấy các ký hiệu trong tệp đối tượng và quá trình xây dựng không thành công.

Bây giờ giải pháp thay thế để ẩn các chi tiết triển khai quan trọng là gì? Như chúng ta đã biết mục tiêu chính đằng sau việc tách giao diện khỏi việc triển khai là ẩn các chi tiết triển khai ở dạng nhị phân. Đây là nơi bạn phải tách các cấu trúc dữ liệu và thuật toán. Các lớp mẫu của bạn phải chỉ đại diện cho các cấu trúc dữ liệu chứ không phải các thuật toán. Điều này cho phép bạn ẩn các chi tiết triển khai có giá trị hơn trong các thư viện lớp không được tạo khuôn mẫu riêng biệt, các lớp bên trong sẽ hoạt động trên các lớp mẫu hoặc chỉ sử dụng chúng để giữ dữ liệu. Lớp mẫu thực sự sẽ chứa ít mã hơn để gán, lấy và đặt dữ liệu. Phần còn lại của công việc sẽ được thực hiện bởi các lớp thuật toán.

Tôi hy vọng cuộc thảo luận này sẽ hữu ích.


2
"phải hiểu rằng lớp mẫu hoàn toàn không phải là một lớp" - có phải ngược lại không? Mẫu lớp là một khuôn mẫu. "Lớp mẫu" đôi khi được sử dụng thay cho "tạo khuôn mẫu" và sẽ là một lớp thực tế.
Xupicor

Chỉ để tham khảo, nói không có cách giải quyết là không đúng! Tách Cấu trúc dữ liệu khỏi các phương thức cũng là một ý tưởng tồi vì nó bị phản đối bởi tính đóng gói. Có một cách giải quyết tuyệt vời mà bạn có thể sử dụng trong một số trường hợp (tôi tin rằng hầu hết) ở đây: stackoverflow.com/questions/495021/…
Sheric

@Xupicor, bạn nói đúng. Về mặt kỹ thuật "Mẫu lớp" là những gì bạn viết để bạn có thể khởi tạo một "Lớp Mẫu" và đối tượng tương ứng của nó. Tuy nhiên, tôi tin rằng trong một thuật ngữ chung, việc sử dụng cả hai thuật ngữ thay thế cho nhau sẽ không hoàn toàn sai, bản thân cú pháp để xác định "Mẫu lớp" bắt đầu bằng từ "mẫu" chứ không phải "lớp".
Sharjith N.

@Sheric, tôi không nói rằng không có cách giải quyết nào. Trên thực tế, tất cả những gì có sẵn chỉ là cách giải quyết để bắt chước sự tách biệt giữa giao diện và triển khai trong trường hợp các lớp mẫu. Không có cách giải quyết nào trong số đó hoạt động mà không cần khởi tạo một lớp mẫu được đánh cụ thể. Điều đó dù sao cũng làm tan biến toàn bộ điểm chung của việc sử dụng các mẫu lớp. Tách cấu trúc dữ liệu khỏi thuật toán không giống như tách cấu trúc dữ liệu khỏi phương pháp. Các lớp cấu trúc dữ liệu rất có thể có các phương thức như constructor, getters và setters.
Sharjith N.

Điều gần nhất mà tôi vừa tìm thấy để thực hiện công việc này là sử dụng một cặp tệp .h / .hpp và #include "filename.hpp" ở cuối tệp .h xác định lớp mẫu của bạn. (bên dưới dấu ngoặc nhọn đóng của bạn cho định nghĩa lớp với dấu chấm phẩy). Điều này ít nhất sẽ phân tách chúng theo cấu trúc theo từng tệp và được phép vì cuối cùng, trình biên dịch sao chép / dán mã .hpp của bạn lên #include "filename.hpp" của bạn.
Artorias2718

90

Điều đó là hoàn toàn có thể, miễn là bạn biết mình sẽ cần những tính năng nào.

Thêm mã sau vào cuối stack.cpp và nó sẽ hoạt động:

template class stack<int>;

Tất cả các phương thức không phải khuôn mẫu của ngăn xếp sẽ được khởi tạo và bước liên kết sẽ hoạt động tốt.


7
Trong thực tế, hầu hết mọi người sử dụng một tệp cpp riêng cho việc này - một cái gì đó như stackinstantiations.cpp.
Nemanja Trifunovic

@NemanjaTrifunovic, bạn có thể cho ví dụ về stackinstantiations.cpp trông như thế nào không?
qwerty9967

3
Trên thực tế có những giải pháp khác: codeproject.com/Articles/48575/...
sleepsort

@ Benoît Tôi gặp lỗi lỗi: id không đủ tiêu chuẩn dự kiến ​​trước ';' ngăn xếp mẫu mã thông báo <int>; Bạn có biết tại sao? Cảm ơn!
camino

3
Trên thực tế, cú pháp chính xác là template class stack<int>;.
Paul Baltescu

8

Bạn có thể làm theo cách này

// xyz.h
#ifndef _XYZ_
#define _XYZ_

template <typename XYZTYPE>
class XYZ {
  //Class members declaration
};

#include "xyz.cpp"
#endif

//xyz.cpp
#ifdef _XYZ_
//Class definition goes here

#endif

Điều này đã được thảo luận trong Daniweb

Cũng trong FAQ nhưng sử dụng từ khóa export C ++.


5
includenhập một cpptập tin thường là một ý tưởng tồi tệ. ngay cả khi bạn có lý do hợp lệ cho điều này, tệp - thực sự chỉ là một tiêu đề được tôn vinh - nên được cung cấp một hpphoặc một số phần mở rộng khác (ví dụ tpp) để làm rõ điều gì đang xảy ra, loại bỏ sự nhầm lẫn xung quanh makefileviệc nhắm mục tiêu các tệp thực tế cpp , v.v.
underscore_d

@underscore_d Bạn có thể giải thích tại sao bao gồm một .cpptệp là một ý tưởng tồi tệ?
Abbas

1
@Abbas bởi vì phần mở rộng cpp(hoặc cc, hoặc cbất cứ thứ gì) chỉ ra rằng tệp là một phần của quá trình triển khai, rằng đơn vị dịch kết quả (đầu ra của bộ xử lý trước) có thể biên dịch riêng biệt và nội dung của tệp chỉ được biên dịch một lần. nó không chỉ ra rằng tệp là một phần có thể sử dụng lại của giao diện, được đưa vào tùy ý ở bất cứ đâu. #includeviệc nhập một tệp thực tế cpp sẽ nhanh chóng lấp đầy màn hình của bạn với nhiều lỗi định nghĩa và đúng như vậy. trong trường hợp này, vì có một lý do để #includenó, cppchỉ là lựa chọn sai lầm của phần mở rộng.
underscore_d

@underscore_d Vì vậy, về cơ bản chỉ sử dụng .cpptiện ích mở rộng để sử dụng như vậy là sai . Nhưng sử dụng một câu nói khác .tpplà hoàn toàn ổn, sẽ phục vụ cùng một mục đích nhưng sử dụng một phần mở rộng khác để hiểu dễ dàng / nhanh hơn?
Abbas

1
@Abbas Vâng, cpp/ cc/ etc phải tránh, nhưng đó là một ý tưởng tốt để sử dụng một cái gì đó khác hơn hpp- ví dụ tpp, tccvv - vì vậy bạn có thể tái sử dụng phần còn lại của tên tập tin và chỉ ra rằng tpptập tin, mặc dù nó hoạt động như một tiêu đề, giữ việc triển khai ngoài dòng của các khai báo mẫu trong tương ứng hpp. Vì vậy, bài đăng này bắt đầu với một tiền đề tốt - tách các khai báo và định nghĩa thành 2 tệp khác nhau, có thể dễ dàng hơn để tìm kiếm / grep hoặc đôi khi được yêu cầu do các phụ thuộc vòng tròn IME - nhưng sau đó kết thúc tệ bằng cách cho rằng tệp thứ 2 có phần mở rộng sai
underscore_d

6

Không, không thể. Không phải không có exporttừ khóa, mà cho tất cả các ý định và mục đích không thực sự tồn tại.

Điều tốt nhất bạn có thể làm là đặt các triển khai chức năng của mình vào tệp ".tcc" hoặc ".tpp" và #include tệp .tcc ở cuối tệp .hpp của bạn. Tuy nhiên đây chỉ là mỹ phẩm; nó vẫn giống như việc triển khai mọi thứ trong tệp tiêu đề. Đây chỉ đơn giản là giá bạn phải trả cho việc sử dụng các mẫu.


3
Câu trả lời của bạn là không đúng. Bạn có thể tạo mã từ một lớp mẫu trong tệp cpp, với điều kiện bạn biết các đối số mẫu cần sử dụng. Xem câu trả lời của tôi để biết thêm thông tin.
Benoît

2
Đúng, nhưng điều này đi kèm với hạn chế nghiêm trọng là cần cập nhật tệp .cpp và biên dịch lại mỗi khi một loại mới được giới thiệu sử dụng mẫu, điều này có lẽ không phải là điều OP nghĩ đến.
Charles Salvia,

3

Tôi tin rằng có hai lý do chính để cố gắng tách mã mẫu thành một tiêu đề và một cpp:

Một là cho sự thanh lịch đơn thuần. Tất cả chúng ta đều thích viết mã khó đọc, quản lý và có thể sử dụng lại sau này.

Khác là giảm thời gian biên dịch.

Tôi hiện đang (như mọi khi) phần mềm mô phỏng mã hóa kết hợp với OpenCL và chúng tôi muốn giữ mã để nó có thể chạy bằng cách sử dụng loại float (cl_float) hoặc double (cl_double) nếu cần tùy thuộc vào khả năng HW. Ngay bây giờ, điều này được thực hiện bằng cách sử dụng #define REAL ở đầu mã, nhưng điều này không được thanh lịch cho lắm. Thay đổi độ chính xác mong muốn yêu cầu biên dịch lại ứng dụng. Vì không có loại thời gian chạy thực nào, chúng ta phải sống với điều này trong thời gian này. May mắn thay, các hạt nhân OpenCL được biên dịch trong thời gian chạy và một kích thước đơn giản (REAL) cho phép chúng ta thay đổi thời gian chạy mã hạt nhân cho phù hợp.

Vấn đề lớn hơn nhiều là mặc dù ứng dụng là mô-đun, khi phát triển các lớp bổ trợ (chẳng hạn như những lớp tính toán trước các hằng số mô phỏng) cũng phải được tạo khuôn mẫu. Tất cả các lớp này đều xuất hiện ít nhất một lần trên đầu cây phụ thuộc lớp, vì lớp mẫu cuối cùng Mô phỏng sẽ có một phiên bản của một trong các lớp nhà máy này, có nghĩa là thực tế mỗi khi tôi thực hiện một thay đổi nhỏ đối với lớp nhà máy, toàn bộ phần mềm phải được xây dựng lại. Điều này rất khó chịu, nhưng tôi dường như không thể tìm ra giải pháp tốt hơn.


2

Chỉ khi bạn #include "stack.cppở cuối stack.hpp. Tôi chỉ đề xuất phương pháp này nếu việc triển khai tương đối lớn và nếu bạn đổi tên tệp .cpp thành một phần mở rộng khác, để phân biệt nó với mã thông thường.


4
Nếu đang làm điều này, bạn sẽ muốn thêm #ifndef STACK_CPP (và bạn bè) vào tệp stack.cpp của mình.
Stephen Newell

Đánh bại tôi trước gợi ý này. Tôi cũng không thích cách tiếp cận này vì lý do phong cách.
luke

2
Đúng vậy, trong trường hợp như vậy, tệp thứ 2 chắc chắn không nên có phần mở rộng cpp( cchoặc bất cứ thứ gì) vì điều đó hoàn toàn trái ngược với vai trò thực sự của nó. Thay vào đó, nó phải được cung cấp một phần mở rộng khác cho biết đó là (A) một tiêu đề và (B) một tiêu đề sẽ được đưa vào cuối một tiêu đề khác. Tôi sử dụng tppcho điều này, một cách dễ dàng cũng có thể đại diện cho tem pchậm trễ im plặng (định nghĩa ngoài dòng). Tôi lan man thêm về điều này ở đây: stackoverflow.com/questions/1724036/…
underscore_d

2

Đôi khi có thể ẩn hầu hết việc triển khai trong tệp cpp, nếu bạn có thể trích xuất chức năng chung cho tất cả các tham số mẫu vào lớp không phải mẫu (có thể là kiểu không an toàn). Sau đó, tiêu đề sẽ chứa các cuộc gọi chuyển hướng đến lớp đó. Cách tiếp cận tương tự được sử dụng, khi chiến đấu với vấn đề "tiêu bản phồng".


+1 - mặc dù nó không hoạt động tốt trong hầu hết thời gian (ít nhất, không thường xuyên như tôi muốn)
peterchen

2

Nếu bạn biết loại ngăn xếp của mình sẽ được sử dụng, bạn có thể khởi tạo chúng một cách nhanh chóng trong tệp cpp và giữ tất cả mã có liên quan ở đó.

Cũng có thể xuất các tệp này qua các tệp DLL (!) Nhưng khá khó để sử dụng đúng cú pháp (kết hợp dành riêng cho MS của __declspec (dllexport) và từ khóa xuất).

Chúng tôi đã sử dụng nó trong một lib toán học / geom được tạo khuôn mẫu kép / float, nhưng có khá nhiều mã. (Tôi đã tìm kiếm nó vào thời điểm đó, tuy nhiên, không có mã đó hôm nay.)


2

Vấn đề là một mẫu không tạo ra một lớp thực tế, nó chỉ là một mẫu cho trình biên dịch biết cách tạo một lớp. Bạn cần tạo một lớp cụ thể.

Cách dễ dàng và tự nhiên là đặt các phương thức trong tệp tiêu đề. Nhưng có một cách khác.

Trong tệp .cpp của bạn, nếu bạn có tham chiếu đến mọi khởi tạo và phương pháp mẫu mà bạn yêu cầu, trình biên dịch sẽ tạo chúng ở đó để sử dụng trong suốt dự án của bạn.

stack.cpp mới:

#include <iostream>
#include "stack.hpp"
template <typename Type> stack<Type>::stack() {
        std::cerr << "Hello, stack " << this << "!" << std::endl;
}
template <typename Type> stack<Type>::~stack() {
        std::cerr << "Goodbye, stack " << this << "." << std::endl;
}
static void DummyFunc() {
    static stack<int> stack_int;  // generates the constructor and destructor code
    // ... any other method invocations need to go here to produce the method code
}

8
Bạn không cần hàm dummey: Sử dụng 'template stack <int>;' Điều này buộc cài đặt mẫu vào đơn vị biên dịch hiện tại. Rất hữu ích nếu bạn xác định một mẫu nhưng chỉ muốn một vài triển khai cụ thể trong lib được chia sẻ.
Martin York

@Martin: bao gồm tất cả các chức năng thành viên? Điều đó thật tuyệt. Bạn nên thêm đề xuất này vào chuỗi "tính năng C ++ ẩn".
Mark Ransom vào

@LokiAstari Tôi đã tìm thấy một bài viết về điều này trong trường hợp có ai muốn tìm hiểu thêm: cplusplus.com/forum/articles/14272
Andrew Larsson

1

Bạn cần có mọi thứ trong tệp hpp. Vấn đề là các lớp không thực sự được tạo cho đến khi trình biên dịch thấy rằng chúng cần đến bởi một số tệp cpp KHÁC - vì vậy nó phải có tất cả mã có sẵn để biên dịch lớp mẫu tại thời điểm đó.

Một điều mà tôi có xu hướng làm là cố gắng chia các mẫu của mình thành một phần không theo khuôn mẫu chung (có thể được phân chia giữa cpp / hpp) và phần mẫu dành riêng cho loại kế thừa lớp không theo khuôn mẫu.


0

Bởi vì các mẫu được biên dịch khi được yêu cầu, điều này buộc phải hạn chế đối với các dự án nhiều tệp: việc triển khai (định nghĩa) của một lớp hoặc chức năng của mẫu phải nằm trong cùng một tệp với phần khai báo của nó. Điều đó có nghĩa là chúng ta không thể tách giao diện trong một tệp tiêu đề riêng biệt và chúng ta phải bao gồm cả giao diện và triển khai trong bất kỳ tệp nào sử dụng các mẫu.


0

Một khả năng khác là làm điều gì đó như:

#ifndef _STACK_HPP
#define _STACK_HPP

template <typename Type>
class stack {
    public:
            stack();
            ~stack();
};

#include "stack.cpp"  // Note the include.  The inclusion
                      // of stack.h in stack.cpp must be 
                      // removed to avoid a circular include.

#endif

Tôi không thích gợi ý này vì vấn đề phong cách, nhưng nó có thể phù hợp với bạn.


1
Tiêu đề thứ 2 được tôn vinh được đưa vào ít nhất phải có một phần mở rộng khác ngoài cppđể tránh nhầm lẫn với các tệp nguồn thực tế . Các đề xuất phổ biến bao gồm tpptcc.
underscore_d

0

Từ khóa 'export' là cách để tách việc triển khai mẫu khỏi khai báo mẫu. Điều này đã được giới thiệu trong tiêu chuẩn C ++ mà không có triển khai hiện có. Trong quá trình thực sự chỉ có một vài trình biên dịch thực sự triển khai nó. Đọc thông tin chuyên sâu tại bài viết Thông tin CNTT về xuất khẩu


1
Đây gần như là một câu trả lời chỉ có liên kết và liên kết đó đã chết.
underscore_d

0

1) Hãy nhớ lý do chính để tách các tệp .h và .cpp là để ẩn việc triển khai lớp dưới dạng mã Obj được biên dịch riêng có thể được liên kết với mã của người dùng bao gồm .h của lớp.

2) Các lớp không phải mẫu có tất cả các biến được định nghĩa cụ thể và cụ thể trong các tệp .h và .cpp. Vì vậy trình biên dịch sẽ có thông tin cần thiết về tất cả các kiểu dữ liệu được sử dụng trong lớp trước khi biên dịch / dịch  tạo đối tượng / mã máy Các lớp mẫu không có thông tin về kiểu dữ liệu cụ thể trước khi người dùng của lớp khởi tạo một đối tượng truyền dữ liệu cần thiết kiểu:

        TClass<int> myObj;

3) Chỉ sau khi khởi tạo này, trình biên dịch tạo ra phiên bản cụ thể của lớp mẫu để khớp với (các) kiểu dữ liệu đã truyền.

4) Do đó, .cpp KHÔNG thể được biên dịch riêng biệt mà không cần biết kiểu dữ liệu cụ thể của người dùng. Vì vậy, nó phải ở dưới dạng mã nguồn trong “.h” cho đến khi người dùng chỉ định kiểu dữ liệu được yêu cầu sau đó, nó có thể được tạo thành một kiểu dữ liệu cụ thể sau đó được biên dịch


0

Nơi bạn có thể muốn thực hiện việc này là khi bạn tạo kết hợp thư viện và tiêu đề, đồng thời ẩn việc triển khai đối với người dùng. Do đó, cách tiếp cận được đề xuất là sử dụng thuyết minh rõ ràng, vì bạn biết phần mềm của mình dự kiến ​​sẽ cung cấp những gì và bạn có thể ẩn các triển khai.

Một số thông tin hữu ích tại đây: https://docs.microsoft.com/en-us/cpp/cpp/explicit-instantiation?view=vs-2019

Đối với cùng một ví dụ của bạn: Stack.hpp

template <class T>
class Stack {

public:
    Stack();
    ~Stack();
    void Push(T val);
    T Pop();
private:
    T val;
};


template class Stack<int>;

stack.cpp

#include <iostream>
#include "Stack.hpp"
using namespace std;

template<class T>
void Stack<T>::Push(T val) {
    cout << "Pushing Value " << endl;
    this->val = val;
}

template<class T>
T Stack<T>::Pop() {
    cout << "Popping Value " << endl;
    return this->val;
}

template <class T> Stack<T>::Stack() {
    cout << "Construct Stack " << this << endl;
}

template <class T> Stack<T>::~Stack() {
    cout << "Destruct Stack " << this << endl;
}

main.cpp

#include <iostream>
using namespace std;

#include "Stack.hpp"

int main() {
    Stack<int> s;
    s.Push(10);
    cout << s.Pop() << endl;
    return 0;
}

Đầu ra:

> Construct Stack 000000AAC012F8B4
> Pushing Value
> Popping Value
> 10
> Destruct Stack 000000AAC012F8B4

Tuy nhiên, tôi không hoàn toàn thích cách tiếp cận này, bởi vì điều này cho phép ứng dụng tự bắn vào chân, bằng cách chuyển các kiểu dữ liệu không chính xác đến lớp mẫu. Ví dụ, trong hàm main, bạn có thể chuyển các kiểu khác có thể được chuyển đổi ngầm thành int như s.Push (1.2); và đó chỉ là xấu theo quan điểm của tôi.


-3

Tôi đang làm việc với Visual studio 2010, nếu bạn muốn chia tệp của mình thành .h và .cpp, hãy bao gồm tiêu đề cpp của bạn ở cuối tệp .h

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.