Câu hỏi này đưa ra một ví dụ rõ ràng về cách bạn có thể sử dụng macro một cách tồi tệ. Để xem các ví dụ khác (và được giải trí) xem câu hỏi này .
Phải nói rằng, tôi sẽ đưa ra các ví dụ trong thế giới thực về những gì tôi cho là kết hợp tốt các macro.
Ví dụ đầu tiên xuất hiện trong CppUnit , là khung kiểm tra đơn vị. Giống như bất kỳ khung thử nghiệm tiêu chuẩn nào khác, bạn tạo một lớp thử nghiệm và sau đó bạn phải bằng cách nào đó chỉ định phương thức nào sẽ được chạy như một phần của thử nghiệm.
#include <cppunit/extensions/HelperMacros.h>
class ComplexNumberTest : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE( ComplexNumberTest );
CPPUNIT_TEST( testEquality );
CPPUNIT_TEST( testAddition );
CPPUNIT_TEST_SUITE_END();
private:
Complex *m_10_1, *m_1_1, *m_11_2;
public:
void setUp();
void tearDown();
void testEquality();
void testAddition();
}
Như bạn có thể thấy, lớp có một khối macro là phần tử đầu tiên. Nếu tôi đã thêm một phương thức mới testSubtraction
, rõ ràng bạn cần phải làm gì để đưa nó vào trong quá trình chạy thử.
Các khối macro này mở rộng ra một cái gì đó như thế này:
public:
static CppUnit::Test *suite()
{
CppUnit::TestSuite *suiteOfTests = new CppUnit::TestSuite( "ComplexNumberTest" );
suiteOfTests->addTest( new CppUnit::TestCaller<ComplexNumberTest>(
"testEquality",
&ComplexNumberTest::testEquality ) );
suiteOfTests->addTest( new CppUnit::TestCaller<ComplexNumberTest>(
"testAddition",
&ComplexNumberTest::testAddition ) );
return suiteOfTests;
}
Mà bạn thích đọc và duy trì?
Một ví dụ khác là trong khung Microsoft MFC, nơi bạn ánh xạ các chức năng thành các thông báo:
BEGIN_MESSAGE_MAP( CMyWnd, CMyParentWndClass )
ON_MESSAGE( WM_MYMESSAGE, OnMyMessage )
ON_COMMAND_RANGE(ID_FILE_MENUITEM1, ID_FILE_MENUITEM3, OnFileMenuItems)
// ... Possibly more entries to handle additional messages
END_MESSAGE_MAP( )
Vậy, những điều phân biệt "Macros tốt" với loại ác quỷ khủng khiếp là gì?
Họ thực hiện một nhiệm vụ không thể đơn giản hóa bằng bất kỳ cách nào khác. Viết một macro để xác định tối đa giữa hai yếu tố là sai, bởi vì bạn có thể đạt được điều tương tự bằng cách sử dụng một phương thức mẫu. Nhưng có một số tác vụ phức tạp (ví dụ: ánh xạ mã thông báo đến các hàm thành viên) mà ngôn ngữ C ++ không xử lý một cách tao nhã.
Họ có một cách sử dụng cực kỳ nghiêm ngặt, chính thức. Trong cả hai ví dụ này, các khối macro được thông báo bằng cách bắt đầu và kết thúc macro và phần giữa các macro sẽ chỉ xuất hiện bên trong các khối này. Bạn có C ++ bình thường, bạn xin phép một thời gian ngắn với một khối macro và sau đó bạn trở lại bình thường. Trong các ví dụ "macro ác", các macro nằm rải rác trong mã và người đọc không may không có cách nào biết khi nào các quy tắc C ++ được áp dụng và khi nào thì không.