Embedded System (6) : 객체 지향 프로그래밍, Qt & GUI Framework 예제
객체 지향 프로그래밍 (Object Oriented Programming)
프로그램을 객체라는 기본 단위로 나누고, 상호작용으로 구현하는 방식
함수 기반 절차 지향 프로그래밍 --> 소스 코드 변경 시, 함수들이 여러 곳에 영향을 끼칠 수 있어 유지 보수가 어려움
OOP는 이런 한계점을 극복
구조체 vs 클래스
단순하게 구조체에 함수 + *접근제한자가 추가된 것
접근 제한자 (Access Modifier)
- 클래스 내에 멤버(필드, 메서드, 속성, 이벤트 등)에게 접근하는 것을 제한하는 역할
- 클래스 멤버의 default는 private / 구조체 멤버의 default는 public
접근 제한자 | 같은 클래스에서의 접근 | 하위 클래스에서의 접근 | 모든 곳으로부터의 접근 |
private | O | X | X |
protected | O | O | X |
public | O | O | O |
OOP 구조
class 정의 시, 메모리에는 할당되지 않음 // 이를 인터페이스라고 함
캡슐화
객체가 구현된 방식의 세부 정보를 사용자로부터 숨기면서 유지하는 방식
- 사용자는 객체의 공개 인터페이스를 통해 접근할 수 있다
- 클래스의 멤버변수 구현 세부정보는 private로 설정하고, 멤버함수 공개 인터페이스는 public으로 설정
C++ : 객체 지향 + 절차 지향 - private / public이 존재 --> 캡슐화에 유리
Java : 객체 지향 - public만 존재
getter / setter
클래스의 private 멤버변수 필드에 접근할 수 있도록 만든 멤버함수 메서드
- private 멤버변수의 값을 바꿀 때, set + 함수이름
- private 멤버변수의 값을 가져올 때, get + 함수이름
객체 생성 방법
using namespace std;
class Sol {
private:
int radius = 10;
};
int main() {
// 1. Stack에 선언
Sol me1;
// 2. Heap에 선언
// 메모리 누수 방지를 위해 꼭 delete를 해줘야 함
Sol* me2 = new Sol();
delete me2;
return 0;
}
객체 생성자 및 초기화
// 생성자 --> class 이름과 같은 함수 이름을 사용
class Circle{
private:
double radius;
public:
Circle(); // 기본 생성자
Circle(double r); // 매개변수가 있는 생성자
Circle(const Circle& circle); // 복사 생성자
};
------------------------------------------
// 초기화 --> 대입 연산자 활용
// 1. this 활용
Marine::Marine(int hp, int power, double speed)
{
this->hp = hp;
this->power = power;
this->speed = speed;
}
// 2. 멤버 초기화 리스트 활용
// - ":" 로 시작
// - "," 로 초기화할 멤버 변수 구분
// - ";" 으로 끝나지 않음
Marine::Marine(int h, int p, double s):hp(h),power(p),speed(s)
{
// 위처럼 하면, 생성자 본문에서 멤버에 값을 할당하는 연산은 안해도 됨
}
소멸자
// 생성자 --> class 이름과 같은 함수 이름을 사용
class Circle{
private:
double radius;
public:
Circle();
Circle(double r);
Circle(const Circle& circle);
~Circle();
};
이름 앞에 ~ 사용, public이 필수 / 객체에 할당된 메모리를 해제
상속
일반적으로 상속은 부모가 가진 요소들을 자식들이 물려받아 사용하는 것을 의미
OOP에서 상속은, 부모 / 자식 관계보다는 "코드 중복 방지" 를 위해 공통적인 요소를 일반화시킨 것
#include <iostream>
class Machine {
public:
std::string ver;
};
class Robot : public Machine {
public:
void run()
{
std::cout << "Hi" << std::endl;
}
};
int main() {
Robot* a = new Robot();
a->run();
a->run();
a->ver = "1.99";
return 0;
}
Qt GUI Framework
C++ 기반 GUI App 개발 시 널리 쓰이는 프레임워크
- 다른 플랫폼으로 porting이 자유로움
- Windows, Linux, MacOS, Android 등 지원
Qt 라이선스
- Commercial 라이선스
- 상용적으로 사용 가능
- 소기업은 약 50만원 / 년
- 그 외 기업은 약 450만원 / 년
- Opensource 라이선스
- GPL : 모든 소스코드를 공개해야 함 (비 상업용으로 사용)
(보통 Qt Chart를 이용해서 개발한다 하면, Qt chart의 라이센스가 GPL이었으면 QT chart를 이용한 코드만 공개)
- LGPL : 특정 모듈을 쓰지 않으면 LGPL로 (상업용으로 사용 가능)
Python으로 Qt 다루기
*Python Binding : 다른 언어로 제작된 library를 python으로 호출할 수 있는 연결 모듈을 의미
유명한 Python Binding Set
1. PySide : Qt 공식 Framework, LGPL 기본 (일부 GPL)
2. PyQt : 비공식, reference가 많음, GPL / 사용 (60 만원 / 년)
예제
from PySide6.QtWidgets import *
def ifClicked(): # 버튼이 클릭되었을 때 실행될 함수를 정의
alert = QMessageBox() # 새로운 메시지 박스 인스턴스를 생성
alert.setText(tbox.text()) # 메시지 박스에 텍스트 상자의 텍스트를 설정
alert.exec() # 메시지 박스를 실행
app = QApplication() # QApplication 인스턴스를 생성
win = QWidget() # QWidget 인스턴스를 생성
win.setWindowTitle("forPractice") # 창 제목을 설정
win.setGeometry(0, 0, 400, 300) # 창의 위치와 크기를 설정
tbox = QLineEdit(win) # 텍스트 상자를 생성하고 창에 추가
btn = QPushButton("PUSH", win) # 버튼을 생성하고 창에 추가
hlay = QHBoxLayout() # 수평 레이아웃을 생성
hlay.addWidget(tbox) # 텍스트 상자를 레이아웃에 추가
hlay.addWidget(btn) # 버튼을 레이아웃에 추가
win.setLayout(hlay) # 창의 레이아웃을 설정
btn.clicked.connect(ifClicked) # 버튼 클릭 이벤트를 ifClicked 함수와 연결
win.show() # 창을 활성화
app.exec() # 애플리케이션을 실행
from PySide6.QtWidgets import *
def setText(): # 나이 확인 버튼 클릭 시 실행되는 함수를 정의
targetText = line2.text() # 나이 입력창의 텍스트를 가져옴
if not 0 < int(targetText) < 150:
warn3.setText("나이가 너무 많습니다") # 메시지를 출력
else:
warn3.setText("통과")
def validation(): # 회원가입 버튼 클릭 시 실행되는 함수를 정의
alert = QMessageBox() # 메시지 박스 인스턴스를 생성
targetText = line1.text() # 이름 입력창의 텍스트를 가져옴
if 1 <= len(targetText) <= 4:
alert.setText("회원가입 성공!") # 메시지를 출력
else:
alert.setText("이름은 1~4글자 필수")
alert.exec() # 메시지 박스를 실행합니다.
app = QApplication() # QApplication 인스턴스를 생성
win = QWidget() # QWidget 인스턴스를 생성
form = QFormLayout() # QFormLayout 인스턴스를 생성합
line1 = QLineEdit() # 이름 입력창을 생성
form.addRow("name", line1) # 이름 입력창을 레이아웃에 추가
line2 = QLineEdit() # 나이 입력창을 생성
btn2 = QPushButton("나이확인") # 나이 확인 버튼을 생성
btn2.clicked.connect(setText) # 버튼 클릭 시 setText 함수가 실행되도록 연결
hlay2 = QHBoxLayout() # 수평 레이아웃을 생성
hlay2.addWidget(line2) # 나이 입력창을 레이아웃에 추가
hlay2.addWidget(btn2) # 나이 확인 버튼을 레이아웃에 추가
form.addRow("age", hlay2) # 나이 확인 레이아웃을 폼 레이아웃에 추가
warn3 = QLabel("") # 경고 레이블을 생성
form.addWidget(warn3) # 경고 레이블을 폼 레이아웃에 추가
btn3 = QPushButton("회원가입") # 회원가입 버튼을 생성
form.addRow(btn3) # 회원가입 버튼을 폼 레이아웃에 추가
btn3.clicked.connect(validation) # 버튼 클릭 시 validation 함수가 실행되도록 연결
`