private 이 기본적으로 생략이 되있어서 오류가 남.
추가로 struct는 public이 기본이다.
멤버 변수는 감추기/은닉하기 위해서 private에 기본으로 둔다.
getter, setter 객체지향에서 중요한 문법이다.
객체지향에서 변수를 그냥 사용하는 것은 위험하기 때문에 공통된 자원인 자료형들은 private이나 protected (C++, java 등)에서 선언하고 public에 getter, setter로 함수를 따로 만들어서 사용하는 것이 좋습니다.
이 C++ 코드는 Dog라는 클래스를 정의하고, 객체를 생성해서 멤버 변수에 값을 설정하고 출력하는 예제입니다. 아래에 각 부분을 자세히 설명해드릴게요:
🐶 클래스 정의: Dog
class Dog {
private:
int age;
double weight;
- age와 weight는 private 멤버 변수로 외부에서 직접 접근할 수 없어요.
- 정보 은닉(Encapsulation)을 통해 객체의 내부 상태를 보호합니다.
🔧 생성자와 소멸자
Dog() : age(0), weight(0.0) {}
~Dog() {}
- 생성자: 객체가 생성될 때 age와 weight를 기본값으로 초기화합니다.
- 소멸자: 객체가 소멸될 때 호출되지만, 여기서는 특별한 작업은 하지 않아요.
🧩 멤버 함수들
void setAge(int a) { age = a; }
int getAge() const { return age; }
void setWeight(double w) { weight = w; }
double getWeight() const { return weight; }
- setAge, setWeight: 객체의 나이와 몸무게를 설정하는 setter 함수
- getAge, getWeight: 값을 반환하는 getter 함수
- const 키워드는 해당 함수가 멤버 변수를 변경하지 않음을 보장해요.
🗣 행동 함수
void cry() { std::cout << "멍멍\n"; }
- cry() 함수는 강아지가 짖는 소리를 출력합니다. 귀엽죠 😄
🧪 main() 함수
int main() {
Dog coco;
coco.setAge(1);
coco.setWeight(2.5);
std::cout << coco.getAge() << " " << coco.getWeight() << '\n';
coco.cry();
}
- Dog 클래스의 객체 coco를 생성
- setAge와 setWeight로 값을 설정
- getAge와 getWeight로 값을 출력
- cry()를 호출해 "멍멍"을 출력
🧠 요약
구성 요소역할
private | 멤버 변수 보호 |
public | 외부에서 접근 가능한 함수들 |
생성자/소멸자 | 객체 초기화 및 정리 |
set/get | 값 설정 및 반환 |
cry() | 행동 표현 |
아래는 C++로 작성된 Dog 클래스를 각각 C#과 Java 스타일로 변환한 코드입니다. 두 언어 모두 객체 지향적이지만, 문법과 입출력 방식에 차이가 있어요.
🟦 C# 버전
using System;
class Dog
{
private int age;
private double weight;
public Dog()
{
age = 0;
weight = 0.0;
}
public int Age
{
get { return age; }
set { age = value; }
}
public double Weight
{
get { return weight; }
set { weight = value; }
}
public void Cry()
{
Console.WriteLine("멍멍");
}
}
class Program
{
static void Main()
{
Dog coco = new Dog();
coco.Age = 1;
coco.Weight = 2.5;
Console.WriteLine($"{coco.Age} {coco.Weight}");
coco.Cry();
}
}
✅ 특징:
- C#에서는 get/set을 속성(Property)으로 표현
- Console.WriteLine으로 출력
- 클래스 이름은 Program으로 메인 함수 포함
☕ Java 버전
public class Dog {
private int age;
private double weight;
public Dog() {
age = 0;
weight = 0.0;
}
public void setAge(int a) {
age = a;
}
public int getAge() {
return age;
}
public void setWeight(double w) {
weight = w;
}
public double getWeight() {
return weight;
}
public void cry() {
System.out.println("멍멍");
}
public static void main(String[] args) {
Dog coco = new Dog();
coco.setAge(1);
coco.setWeight(2.5);
System.out.println(coco.getAge() + " " + coco.getWeight());
coco.cry();
}
}
✅ 특징:
- Java는 main 메서드가 static이어야 함
- System.out.println으로 출력
- 속성은 get/set 메서드로 접근
- Java는 Spring Framework 덕분에 생략이 가능함
함수를 만드는 것을 정의라고 한다.
함수를 사용하는 것을 호출이라고 한다.
함수를 세미콜론을 붙여서 하는 것을 선언이라고 한다.
코드 길이가 긴 경우가 많아 2번 방법이 효율적임
1번은 정의를 그대로 했기 때문에 변수와 함수, 다른 자원들이 추가 될수록 관리하기가 힘들기 때문에
2번을 많이 사용한다. 2번은 헤더파일로 class를 따로 빼서 선언만 하고
cpp 파일에 class가 포함 되어 있는 헤더파일을 포함시키고 정의만 하는 것이 일반적인 방법이다.
클래스 선언부(class 안)와 클래스 외부(스코프 밖)에서 멤버 함수를 정의하는 방식을 혼합해서 사용한 예제입니다.
🐶 현재 코드 구조
- 클래스 안: 함수 원형(프로토타입)만 선언
- 클래스 밖: Dog::함수이름 형태로 실제 구현 작성
- 단, cry() 함수는 클래스 안에서 바로 정의됨 (inline 함수처럼 동작)
📌 클래스 안에서 정의하는 경우
class Dog {
public:
void cry() { std::cout << "멍멍\n"; } // 클래스 안에서 정의
};
✅ 장점
- 코드가 짧고 간단할 때는 가독성이 좋음
- 컴파일러가 자동으로 inline 함수로 처리할 수 있어 성능 최적화 가능
- 헤더 파일 하나만으로 선언과 구현을 모두 확인 가능
❌ 단점
- 클래스가 커질수록 가독성이 떨어짐 (헤더 파일이 너무 길어짐)
- 모든 구현이 헤더에 들어가면, 코드 변경 시 재컴파일 범위가 커짐
- inline 최적화가 항상 이득은 아님 (코드 크기 증가 가능)
📌 클래스 밖에서 정의하는 경우
class Dog {
public:
void cry(); // 선언만
};
void Dog::cry() { std::cout << "멍멍\n"; } // 클래스 밖에서 정의
✅ 장점
- 헤더(.h) 파일에는 인터페이스(선언)만 두고,
소스(.cpp) 파일에는 구현을 두는 구조 → 코드 관리 용이 - 클래스가 커져도 헤더는 깔끔하게 유지됨
- 구현을 바꿔도 인터페이스가 같으면 헤더 수정 불필요 → 재컴파일 최소화
❌ 단점
- 선언과 구현이 분리되므로, 작은 함수는 오히려 번거로움
- 코드 읽을 때 "이 함수가 어떻게 동작하는지" 확인하려면 cpp 파일까지 가야 함
⚖️ 정리
방식장점단점적합한 경우
클래스 안 정의 | 간단, inline 최적화, 한눈에 보기 쉬움 | 헤더가 길어짐, 재컴파일 많음 | 짧고 단순한 함수 (getter/setter, 출력 등) |
클래스 밖 정의 | 인터페이스/구현 분리, 유지보수 용이 | 작은 함수도 분리하면 번거로움 | 복잡한 로직, 큰 프로젝트, 협업 환경 |
👉 그래서 실제 개발에서는 보통:
- 간단한 getter/setter, 짧은 유틸 함수 → 클래스 안에서 정의
- 로직이 긴 함수, 복잡한 기능 → 클래스 밖에서 정의
private은 앞에 -
public은 앞에 +
클래스 다이어그램
클래스 다이어그램에서 접근 제어자를 표기할 때는 다음과 같은 기호를 사용합니다:
접근 제어자기호의미
public | + | 어디서든 접근 가능 |
private | - | 클래스 내부에서만 접근 가능 |
protected | # | 같은 클래스와 하위 클래스(상속 관계)에서 접근 가능 |
(package / default, Java 등) | ~ | 같은 패키지 내에서 접근 가능 |
예시 UML 클래스 다이어그램 표기
+ setAge(a: int): void
- age: int
# weight: double
- + setAge(...) → public 메서드
- - age → private 멤버 변수
- # weight → protected 멤버 변수
1번을 쓰기를 권장한다.
namespace로 구분함.
범위 지정 연산자 이것으로 구분을 파악함.
inline 함수를 사용안합니다.
컴파일러가 이미 최적화 해줌.
요즘 C++ 컴파일러들은 inline은 붙이지 않아도, 작은 함수라면 자동으로 인라인 최적화를 해줍니다. 그래서 굳이 inline 키워드를 붙일 필요가 없습니다.
코드 크기 증가 (Code Bloat)
인라인 함수는 호출되는 곳마다 함수 본문이 복사, 삽입되기 때문에, 자주 호출되는 함수라면 실행 속도는 빨라질 수 있지만 바이너리 크기가 커져서 오히려 성능이 떨어질 수도 있습니다.
긴 함수에는 효과 없음
함수가 길거나 복잡하면, 컴파일러가 inline을 무시하고 그냥 일반 함수처럼 처리합니다. 즉, 붙여도 소용이 없는 경우가 많습니다.
헤더 파일 의존성 증가
인라인 함수는 보통 헤더 파일에 정의해야 하는데, 이 경우 컴파일 의존성이 커지고 빌드 시간이 늘어날 수 있습니다.
그럼 언제 쓰나?
아주 짧고 자주 호출되는 getter/setter 같은 함수.
매크로 대신 안전하게 쓰고 싶을 때(디버깅, 타입 안전성 확보)
성능이 극도로 중요한 코드에서, 컴파일러가 자동 인라인을 안 해줄 때
클래스 안에서 정의하는 경우에는 자동으로 inline 함수로 간주됩니다.
클래스 밖에서 정의하는 경우에는 자동으로 inline이 되지 않습니다.
성능차이로는 짧은 함수(getter/setter)면 클래스 안에 정의 했을 때 자동으로 인라인 최적화가 적용될 가능성이 크므로 성능상 유리합니다.
긴 함수(로직이 많은 함수)면 인라인을 붙여도 컴파일러가 무시하는 경우가 많아, 사실상 성능 차이는 거의 없습니다.
현대 컴파일러는 inline 키워드보다 자체 최적화 판단을 더 신뢰하는 게 일반적입니다.
결론은 클래스 안에서 바로 정의한 짧은 함수가 인라인 성능 최적화에 더 유리합니다.
하지만 실질적으로는 컴파일러가 알아서 최적화하기 때문에, 성능 차이는 미미하고 코드 가독성과 유지보수성을 기준으로 선택하는 게 더 중요합니다.
#include <iostream>
#include <string>
class Dog {
private:
std::string name;
int age;
double weight;
public:
std::string getName() { return name; }
void setName(std::string n) { name = n; }
int getAge() { return age; }
void setAge(int a) { age = a; }
double getWeight() { return weight; }
void setWeight(double w) { weight = w; }
void cry() { std::cout << "wroof wroof\n"; }
};
int main() {
Dog coco;
coco.setName("coco");
coco.setAge(3);
coco.setWeight(2.5);
std::cout << "Name : " << coco.getName() << "\nAge : " << coco.getAge() << "\nWeight : " << coco.getWeight() << "\n";
std::cout << "coco : ";
coco.cry();
}
'1학년 대학 수업 > C++ 프로그래밍' 카테고리의 다른 글
7주차 중간고사 공지 (0) | 2025.10.16 |
---|---|
7주차 예습 과제 (0) | 2025.10.04 |
5주차 수업 후 과제 (0) | 2025.10.02 |
5주차 예습 과제 (0) | 2025.09.30 |
4주차 수업 후 과제 (0) | 2025.09.25 |