OOP vs Nội tuyến với Arduino


8

Tôi đã lập trình được khá lâu nhưng tôi chưa quen với Lập trình Arduino và AVR. Câu hỏi chính tôi có về lập trình các bộ điều khiển vi mô này là có sự khác biệt lớn trong việc thiết kế mã trong Các lớp hướng đối tượng so với lập trình nội tuyến truyền thống hơn mà tôi đã thấy trong nhiều ví dụ không?

Nói cách khác trong thế giới của Bộ điều khiển Arduino / AVR có tiết kiệm nào với các lớp sử dụng Bộ nhớ và Hiệu suất hoặc ngược lại không?

Nói ví dụ, chúng tôi có một Lớp:

class SomeClass(){

private:
   int x;
   int y;

public:
   void foo();
   void bar();
}

SomeClass thisClass;
thisClass.foo();
thisClass.bar();

Sẽ có bất kỳ hiệu suất hoặc tăng bộ nhớ nào khi thiết kế chương trình theo kiểu nội tuyến hơn như:

int x;
int y;

void foo(){ /*** Do something ***/};
void bar(){ /*** Do more stuff ***/};

Tôi đã thử thực hiện một số tìm kiếm trên Stack Exchange và Google nhưng không thể tìm thấy câu trả lời mà tôi đang tìm kiếm thứ gần nhất tôi có thể tìm thấy là Câu hỏi về Stack Exchange này.

Lý do tôi hỏi về điều này là tôi có một dự án cần phải nhẹ nhất có thể và tôi không rõ làm thế nào tôi nên thiết kế chương trình của mình trong môi trường này.


Biên tập

Cảm ơn bạn đã trả lời, điều này đã làm sáng tỏ mọi thứ. Có một điều mà tôi không rõ lắm.

Giả sử bạn có một lớp mà bạn đang thiết kế sử dụng u8glib như sau:

class UserInterface{
private:
   U8GLIB_ST7920_128X64 Display;

public:
   UserInterface();
}

Bạn sẽ sử dụng "Bộ nhớ động" như thế nào:

UserInterface::UserInterface(){
   UserInterface::Display = U8GLIB_ST7920_128X64(LCD_E_PIN, LCD_RW_PIN, LCD_RS_PIN, U8G_PIN_NONE);
}

Câu trả lời:


2

Câu hỏi chính tôi có về lập trình các bộ điều khiển vi mô này là có sự khác biệt lớn trong việc thiết kế mã trong Các lớp hướng đối tượng so với lập trình nội tuyến truyền thống hơn mà tôi đã thấy trong nhiều ví dụ không?

...

Nói cách khác trong thế giới của Bộ điều khiển Arduino / AVR có tiết kiệm nào với các lớp sử dụng Bộ nhớ và Hiệu suất hoặc ngược lại không?

Có, có một sự khác biệt lớn giữa việc sử dụng C hoặc C ++ cho các hệ thống nhúng quy mô nhỏ như Arduino / AVR. C ++ cho phép cung cấp thêm thông tin để tối ưu hóa trình biên dịch.

Nếu bạn đang triển khai khung OOP, nền tảng hoặc thời gian chạy C ++ và các lớp cũng có thể trợ giúp với kiến ​​trúc và tái sử dụng phần mềm. Trong Cosa, một số mẫu thiết kế OOP được sử dụng để đạt được giao diện cho cả lập trình viên ứng dụng và lập trình điều khiển thiết bị. Phổ biến nhất là đoàn .

Sử dụng các lớp trừu tượng, các hàm thành viên ảo, nội tuyến và các mẫu có thể giúp đạt được hiệu suất thấp hơn và hiệu suất cao hơn so với các triển khai truyền thống. Ví dụ, các lớp Cosa Pin nhanh hơn X5-X10 so với lõi Arduino và đồng thời nhỏ hơn ở dạng in chân. Xin vui lòng xem điểm chuẩn .

Một điều để "không học" từ lập trình C ++ truyền thống là việc sử dụng mới / xóa (malloc / miễn phí). Với kích thước SRAM chỉ một vài Kbyte sử dụng một đống là rất nhiều rủi ro. Câu trả lời là các lớp tĩnh và dữ liệu dựa trên ngăn xếp.

Có nhiều hơn nữa để nói về kiến ​​trúc khung OOP nhưng tôi hy vọng điều này sẽ giúp trả lời các câu hỏi ban đầu của bạn.

Chúc mừng!


Câu trả lời tốt đẹp! Tôi đã cập nhật câu hỏi của mình hỏi về cách di chuyển xung quanh bộ nhớ động (mới / xóa / malloc / miễn phí). Bạn có bất kỳ đầu vào về việc không sử dụng phân bổ bộ nhớ động? Tất cả mọi thứ cần được chia sẻ trong các lớp học là toàn cầu? Điều đó không đúng với tôi, tôi luôn được dạy không sử dụng toàn cầu nếu bạn có thể giúp đỡ.
Andy Braham

Một nhận xét ngắn về ví dụ UserInterface của bạn ở trên. Màn hình thực sự là thành phần đối tượng (không phải tham chiếu / con trỏ) nên bạn không cần mới. Bạn cần phải bắt đầu Hiển thị. Cấu trúc UserInterface sẽ trông giống như thế này. UserInterface::UserInterface() : Display(LCD_E_PIN, LCD_RW_PIN, LCD_RS_PIN, U8G_PIN_NONE) { ... }. Các tham số của hàm tạo Hiển thị cần thiết phải được chuyển đến hàm tạo UserInterface.
Mikael Patel

OOP là tất cả về đóng gói, ẩn dữ liệu, vì vậy việc chia sẻ phải ở mức tối thiểu (không). Mục tiêu là ít nhiều chỉ có một số đối tượng tĩnh toàn cầu tương tác. Họ nắm giữ và che giấu nhà nước toàn cầu. Đối với các đối tượng, dữ liệu thành viên là trạng thái cục bộ không động. Để đạt được mục tiêu, bạn cần lại một loạt các thủ thuật; biến đổi chương trình.
Mikael Patel

Một ví dụ; Hãy xem xét thiết kế của một lớp BitSet có thể có số lượng thành viên thay đổi. Giải pháp rõ ràng là tính toán số byte cần thiết và sử dụng new / malloc. Một cách khác là truyền lưu trữ dưới dạng tham số cho hàm tạo Bitset. Một thay thế thứ ba là một lớp mẫu với số lượng phần tử là tham số. Điều này cho phép một biến thành viên là số byte cần thiết. Vui lòng xem Cosa / BitSet.hh để biết thêm chi tiết về biến thể chuyển đổi chương trình này. Có nhiều biến đổi hơn.
Mikael Patel

Tôi đã cập nhật ví dụ UserInterface của mình, đó có phải là cách tiếp cận đúng hay ít hơn? Tôi nghĩ bây giờ tôi đã hiểu rất rõ về cách thực hiện những gì tôi cần.
Andy Braham

4

Lý do bạn không thể tìm thấy câu trả lời là vì câu trả lời là Có và Không.

Đối với các công cụ lớp cơ bản - xác định lớp của bạn bằng các phương thức, v.v. và khởi tạo các đối tượng từ nó - có một chút khác biệt trong kết quả cuối cùng so với "vanilla" C. Tối ưu hóa của trình biên dịch rất tốt khi hiệu suất chỉ như nhau. Có, có thể có sự gia tăng nhẹ trong việc sử dụng bộ nhớ vì bạn đang chuyển một con trỏ phụ với mỗi lệnh gọi phương thức (thay vì foo(int x)bạn có foo(MyClass *this, int x)) nhưng điều đó quá nhỏ đến mức không thể nhận thấy.

Sự khác biệt lớn đến khi bạn bắt đầu chơi với đa hình và các chủ đề nâng cao khác. Khi bắt đầu thực hiện các chương trình phức tạp này, trình biên dịch không phải lúc nào cũng không thể tìm ra các chức năng nào được yêu cầu và không có chức năng nào, và nó không thể cắt bỏ các chức năng không sử dụng ( "bộ sưu tập rác" ). Vì vậy, bạn cũng có thể kết thúc với mã lớn hơn.

Điều đó không có nghĩa là mã chậm hơn, chỉ là những đoạn mã được treo xung quanh mà không bao giờ làm gì cả.

Tầm quan trọng lớn hơn là quản lý bộ nhớ động của bạn tốt hơn bạn đã quen. Vì có một lượng bộ nhớ nhỏ như vậy, heap rất nhỏ, và kết quả là nó bị phân mảnh rất dễ dàng. Năng động, sáng tạo và phá hủy các đối tượng ( new myClass, delete myClassObject, vv) là rất xấu. Các đối tượng lớp thực sự cần phải được xác định tĩnh (trong phạm vi toàn cầu là phổ biến nhất) hoặc được phân bổ tạm thời trên ngăn xếp (các thể hiện cục bộ). Nếu không, bạn đang yêu cầu sự cố - và điều đầu tiên bạn sẽ biết đó là những điều kỳ lạ xảy ra (không có báo cáo lỗi hoặc ngoại lệ, bạn thấy ...).


Vì vậy, nếu tôi hiểu điều này một cách chính xác trong thế giới lập trình này, các lớp được sử dụng cho vai trò tổ chức và tính di động nhiều hơn OOP thực sự và mọi thứ nên được phân bổ tĩnh và rõ ràng hơn là động. Rất cảm ơn bạn, điều này có ý nghĩa và giải thích lý do tại sao tôi đã nhìn thấy các ví dụ và những gì không được viết theo cách họ đang có.
Andy Braham
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.