오늘은 배열의 평균 구하기와 짝수와 홀수를 풀었다.
// 평균 구하기
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
double solution(int arr[], size_t arr_len) // size_t = unsigned int : 양의 정수 전용 타입
{
int sum = 0; // 합계 저장할 변수 0으로 초기화
for (size_t i = 0; i < arr_len; i++) // size_t 타입의 i 사용
{
sum += arr[i]; // 배열의 i번째 값을 누적해서 합산
}
return (double)sum / arr_len; // 평균 계산
arr_len 은 배열의 길이 = 배열의 크기이므로 평균을 구할 땐 합계 / arr_len을 하면 된다.
// 짝수와 홀수
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
char* solution(int num)
{
if (num % 2 == 0)
{
return (char*)"Even";
}
else
{
return (char*)"Odd";
}
}
// 삼항 연산자 사용
/*
char* solution(int num)
{
return (char*)(num % 2 == 0 ? "Even" : "Odd");
}
*/
if / else문으로 조건을 나눠 2로 나눌 때 나머지가 0이면 짝수, 0이 아니면 홀수를 반환하도록 풀었다. 그리고 C++ 문법 강의에서 들었던 삼항 연산자를 통해서도 풀 수 있을 것 같았다. 조건을 만족하면 A, 만족하지 못하면 B가 나오니 짝수, 홀수를 출력할 수 있다.
강의는 드디어 1주차를 다 들었다!
| 구분 | 설명 | 예 |
|---|---|---|
| 기본 클래스 (Base, 부모 클래스) | 기능을 정의해두는 클래스 다른 클래스가 공통적으로 사용할 기능을 정의 | AAnimal, ACharacter |
| 파생 클래스 (Derived, 자식 클래스) | 기본 클래스를 물려받는 클래스 기능을 그대로 쓰거나 바꾸거나 추가 가능 | ADog, AMyEnemy |
| 장점 | 코드 재사용, 유지보수 쉬움 | 부모 기능도 자식에서 쓸 수 있음 |
protected 외부 접근은 불가능하지만 상속 받은 클래스에서는 접근이 가능함
#include <iostream>
#include <string>
using namespace std;
class Vehicle {
protected:
string color;
int speed;
public:
Vehicle(string c, int s) : color(c), speed(s) {} // 멤버 초기화 리스트
void move() {
cout << "The vehicle is moving at " << speed << " km/h." << endl;
}
void setColor(string c) {
color = c;
}
string getColor() {
return color;
}
};

생성자 괄호 ( ) 뒤에 콜론 : 붙이고 멤버 변수나 부모 클래스 생성자를 초기화함
멤버 초기화 리스트는 생성자의 실제 코드 부분보다 먼저 실행됨
// 멤버 초기화 리스트 X
MyClass() {
member = 10; // 생성된 후 값을 넣는 것 (대입), 생성 → 기본값 → 대입
}
// 멤버 초기화 리스트 O
MyClass() : member(10) {
// 여기 오기 전에 이미 member가 10으로 초기화됨, 생성 → 초기화
}
기본 클래스(Base Class) = 기본이 되는 클래스
→ 함수의 인터페이스만 정의 (실제 내용은 없음 또는 기본값만 있음)
→ 보통 virtual 로 가상 함수를 선언
파생 클래스(Derived Class) = 실제 구현 담당
→ override 로 함수를 재정의(오버라이딩) 해서 실제 동작을 다르게 구현함
virtual 로 선언된 함수는 가상 함수class Animal {
public:
virtual void speak(); // 가상 함수
};class Dog : public Animal {
public:
void speak() override; // 오버라이드 → Dog의 speak로 바뀜
};speak()는 Dog에서 재정의Dog::speak() 의 주소가 들어감int main()
{
Animal* a = new Dog();
a->speak(); // Dog::speak()가 호출됨
}a는 Animal* 이지만 내부에 있는 vptr이 Dog의 vtable을 가리킴Dog::speak() 주소를 찾아감virtual 함수 → V-Table 생성 → override로 재정의 → 실행 시 실제 타입의 함수 호출
| 부분 | 의미 |
|---|---|
Animal* a | 부모 클래스 포인터 |
new Dog() | 자식 클래스 객체를 생성 |
a->speak() | 부모 타입 포인터로 speak() 호출 |
Dog::speak() | 오버라이드 된 자식 함수 |
함수 선언만 있는 함수
인터페이스는 필요하지만 기본 클래스에서 구현할 필요가 없을 때 → 함수 틀만 제공
// 문법
virtual void 함수이름() = 0;
// 예시
class Animal { // 추상 클래스
public:
virtual void speak() = 0; // 순수 가상 함수
};
구현은 없고 = 0 만 있음
이 클래스는 추상 클래스(Abstract Class)가 됨
하나 이상의 순수 가상 함수를 가지는 클래스
→ 스스로는 객체를 만들 수 없고 기반 클래스로만 사용됨
| 구분 | 가상 함수 | 순수 가상 함수 |
|---|---|---|
| 선언 | virtual void func(); | virtual void func() = 0; |
| 구현 여부 | 부모 클래스에 구현 있음 | 구현 없음 (틀만 존재) |
| 오버라이드 | 자식 클래스에서 선택 | 자식 클래스에서 필수 |
| 객체 생성 | 가능 | ❌ 객체 생성 불가 |
| 역할 | 선택적 재정의 | 강제 인터페이스 제공 |
| 상황 | 예시 | 연산자 | 설명 |
|---|---|---|---|
| 객체 | Animal a; | . | 객체 자체로 멤버에 접근 |
| 객체 포인터 | Animal* a = new Animal(); | -> | 포인터로 객체를 가리킬 때 사용 |
int main() {
Animal a; // 객체
Animal* aptr = &a; // 객체 포인터
a.speak(); // 객체 → . 연산자 사용
aptr->speak(); // 포인터 → -> 연산자 사용
}