Topic 4: 정적 멤버와 친구 함수 👥
🎯 학습 목표
- static 멤버 변수와 함수의 개념을 이해할 수 있다
- 정적 멤버와 일반 멤버의 차이점을 설명할 수 있다
- friend 함수와 friend 클래스를 활용할 수 있다
- 클래스 레벨의 데이터를 관리할 수 있다
🌐 Static 멤버: 모두가 공유하는 것
학교 게시판으로 이해하는 Static 📋
일반 멤버 변수는 각 학생이 가진 개인 노트와 같고, static 멤버 변수는 모든 학생이 보는 학교 게시판과 같습니다!
class Student {
private:
string name; // 개인 노트 (각자 다름)
int studentNumber; // 개인 번호 (각자 다름)
static int totalCount; // 학교 게시판 (모두 공유!)
static string schoolName; // 학교 이름 (모두 같음!)
public:
Student(string n) {
name = n;
studentNumber = ++totalCount; // 전체 학생 수 증가
cout << name << " 학생 등록! 학번: " << studentNumber << endl;
}
// static 함수 - 객체 없이도 호출 가능!
static int getTotalCount() {
return totalCount;
}
static string getSchoolName() {
return schoolName;
}
};
// static 멤버 변수 초기화 (클래스 밖에서!)
int Student::totalCount = 0;
string Student::schoolName = "코딩 고등학교";💡 Static 멤버 실습 예제
게임 서버 관리 시스템
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class GameServer {
private:
string playerName;
int playerId;
bool isOnline;
// static 멤버 변수들
static int totalPlayers; // 전체 플레이어 수
static int onlinePlayers; // 현재 접속자 수
static int maxConcurrentUsers; // 최대 동시 접속자 수
static vector<string> serverLog; // 서버 로그
public:
// 생성자 - 플레이어 가입
GameServer(string name) {
playerName = name;
playerId = ++totalPlayers;
isOnline = false;
cout << "🎮 [" << playerName << "] 님이 가입했습니다! (ID: "
<< playerId << ")" << endl;
addLog(playerName + " 가입");
}
// 로그인
void login() {
if (!isOnline) {
isOnline = true;
onlinePlayers++;
// 최대 동시 접속자 갱신
if (onlinePlayers > maxConcurrentUsers) {
maxConcurrentUsers = onlinePlayers;
}
cout << "✅ [" << playerName << "] 로그인!" << endl;
cout << " 현재 접속자: " << onlinePlayers << "명" << endl;
addLog(playerName + " 로그인");
} else {
cout << "❌ 이미 로그인 중입니다!" << endl;
}
}
// 로그아웃
void logout() {
if (isOnline) {
isOnline = false;
onlinePlayers--;
cout << "👋 [" << playerName << "] 로그아웃!" << endl;
cout << " 현재 접속자: " << onlinePlayers << "명" << endl;
addLog(playerName + " 로그아웃");
}
}
// static 함수 - 서버 통계
static void showServerStats() {
cout << "\n=== 🖥️ 서버 통계 ===" << endl;
cout << "총 가입자 수: " << totalPlayers << "명" << endl;
cout << "현재 접속자: " << onlinePlayers << "명" << endl;
cout << "최대 동시 접속자: " << maxConcurrentUsers << "명" << endl;
cout << "==================" << endl;
}
// static 함수 - 로그 추가
static void addLog(string message) {
serverLog.push_back(message);
}
// static 함수 - 로그 출력
static void showLogs() {
cout << "\n=== 📜 서버 로그 ===" << endl;
for (const string& log : serverLog) {
cout << "• " << log << endl;
}
cout << "==================" << endl;
}
};
// static 멤버 변수 초기화
int GameServer::totalPlayers = 0;
int GameServer::onlinePlayers = 0;
int GameServer::maxConcurrentUsers = 0;
vector<string> GameServer::serverLog;
int main() {
// static 함수는 객체 없이도 호출 가능!
GameServer::showServerStats();
// 플레이어들 생성
GameServer player1("김전사");
GameServer player2("이마법사");
GameServer player3("박도적");
// 로그인/로그아웃 테스트
player1.login();
player2.login();
player3.login();
GameServer::showServerStats();
player1.logout();
// 새 플레이어 추가
GameServer player4("최궁수");
player4.login();
GameServer::showServerStats();
GameServer::showLogs();
return 0;
}👫 Friend 함수: 특별한 친구
Friend의 개념 🤝
friend는 클래스의 private 멤버에 접근할 수 있는 특별한 권한을 가진 함수나 클래스입니다!
마치 집 열쇠를 가진 친한 친구와 같아요:
- 일반 사람: 초인종만 누를 수 있음 (public)
- 가족: 집 안 어디든 갈 수 있음 (같은 클래스)
- 친한 친구: 특별히 열쇠를 줘서 들어올 수 있음 (friend)
Friend 함수 예제
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
class Point {
private:
double x;
double y;
public:
Point(double xPos = 0, double yPos = 0) {
x = xPos;
y = yPos;
}
void show() const {
cout << "(" << x << ", " << y << ")";
}
// friend 함수 선언 - 이 함수는 private에 접근 가능!
friend double getDistance(const Point& p1, const Point& p2);
friend class PointManager; // PointManager 클래스는 친구!
};
// friend 함수 구현 - Point의 private 멤버 접근 가능
double getDistance(const Point& p1, const Point& p2) {
double dx = p1.x - p2.x; // private인 x에 접근!
double dy = p1.y - p2.y; // private인 y에 접근!
return sqrt(dx * dx + dy * dy);
}
// friend 클래스
class PointManager {
public:
void movePoint(Point& p, double dx, double dy) {
p.x += dx; // friend이므로 private 접근 가능!
p.y += dy;
cout << "점을 (" << dx << ", " << dy << ") 만큼 이동" << endl;
}
void setOrigin(Point& p) {
p.x = 0; // private 멤버 직접 수정!
p.y = 0;
cout << "원점으로 이동" << endl;
}
};
int main() {
Point p1(3, 4);
Point p2(6, 8);
cout << "점 1: "; p1.show(); cout << endl;
cout << "점 2: "; p2.show(); cout << endl;
// friend 함수 사용
double dist = getDistance(p1, p2);
cout << "두 점 사이의 거리: " << dist << endl;
// friend 클래스 사용
PointManager manager;
manager.movePoint(p1, 2, 3);
cout << "이동 후 점 1: "; p1.show(); cout << endl;
manager.setOrigin(p2);
cout << "원점 이동 후 점 2: "; p2.show(); cout << endl;
return 0;
}🏢 실전 예제: 회사 직원 관리 시스템
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Employee {
private:
string name;
int id;
double salary;
string department;
// static 멤버
static int nextId;
static int totalEmployees;
static double totalSalaryBudget;
public:
// 생성자
Employee(string n, double s, string dept) {
name = n;
id = nextId++;
salary = s;
department = dept;
totalEmployees++;
totalSalaryBudget += salary;
cout << "🆕 신입 사원: " << name << " (사번: " << id << ")" << endl;
}
// 소멸자
~Employee() {
totalEmployees--;
totalSalaryBudget -= salary;
}
// 급여 인상
void raiseSalary(double percent) {
double increase = salary * percent / 100;
totalSalaryBudget -= salary; // 기존 급여 제거
salary += increase;
totalSalaryBudget += salary; // 새 급여 추가
cout << "💰 " << name << "님 급여 " << percent << "% 인상!" << endl;
}
// static 함수 - 회사 통계
static void showCompanyStats() {
cout << "\n=== 🏢 회사 현황 ===" << endl;
cout << "총 직원 수: " << totalEmployees << "명" << endl;
cout << "총 급여 예산: " << totalSalaryBudget << "원" << endl;
if (totalEmployees > 0) {
cout << "평균 급여: " << totalSalaryBudget / totalEmployees << "원" << endl;
}
cout << "==================" << endl;
}
// getter
string getName() const { return name; }
int getId() const { return id; }
// friend 함수 선언 - HR 부서만 급여 정보 접근 가능
friend class HRDepartment;
friend void auditSalary(const Employee& emp);
};
// static 멤버 초기화
int Employee::nextId = 1001;
int Employee::totalEmployees = 0;
double Employee::totalSalaryBudget = 0;
// friend 클래스 - HR 부서
class HRDepartment {
public:
// 급여 정보 출력 (friend이므로 private 접근 가능)
void printSalaryInfo(const Employee& emp) {
cout << "💼 [HR 접근] " << emp.name << "님의 급여: "
<< emp.salary << "원 (부서: " << emp.department << ")" << endl;
}
// 부서 이동
void transferDepartment(Employee& emp, string newDept) {
cout << "🔄 " << emp.name << "님 부서 이동: "
<< emp.department << " → " << newDept << endl;
emp.department = newDept;
}
};
// friend 함수 - 급여 감사
void auditSalary(const Employee& emp) {
cout << "🔍 [감사] 사번 " << emp.id << " " << emp.name
<< "님 급여: " << emp.salary << "원" << endl;
}
int main() {
// 회사 초기 상태
Employee::showCompanyStats();
// 직원 채용
Employee* emp1 = new Employee("김철수", 3000000, "개발팀");
Employee* emp2 = new Employee("이영희", 3500000, "디자인팀");
Employee* emp3 = new Employee("박민수", 4000000, "기획팀");
Employee::showCompanyStats();
// HR 부서 권한 사용
HRDepartment hr;
hr.printSalaryInfo(*emp1);
hr.transferDepartment(*emp2, "마케팅팀");
// 급여 인상
emp1->raiseSalary(10);
// 감사 함수 사용
auditSalary(*emp3);
Employee::showCompanyStats();
// 직원 퇴사
delete emp1;
cout << "😢 김철수님 퇴사" << endl;
Employee::showCompanyStats();
// 메모리 정리
delete emp2;
delete emp3;
return 0;
}📊 Static vs Non-Static 비교
| 특징 | 일반 멤버 | Static 멤버 |
|---|---|---|
| 소속 | 객체마다 개별 | 클래스 전체 공유 |
| 메모리 | 객체 생성 시 할당 | 프로그램 시작 시 할당 |
| 접근 | 객체를 통해 접근 | 클래스명::멤버 |
| this 포인터 | 사용 가능 | 사용 불가 |
| 초기화 | 생성자에서 | 클래스 외부에서 |
🤝 Friend 사용 시 주의사항
✅ 적절한 사용
- 연산자 오버로딩
- 두 클래스 간 긴밀한 협력
- 성능이 중요한 경우
❌ 피해야 할 사용
- 캡슐화 원칙 파괴
- 과도한 friend 선언
- 단순 편의를 위한 사용
💡 핵심 정리
- static 멤버: 모든 객체가 공유하는 클래스 레벨 데이터
- static 함수: 객체 없이 호출 가능한 클래스 함수
- friend 함수: private 멤버에 접근 가능한 특별한 함수
- friend 클래스: 다른 클래스의 private에 접근 가능
✅ 실습 체크리스트
🎉 Unit 10 완료!
축하합니다! 클래스와 객체의 기본을 모두 마스터했습니다! 🎊
이번 Unit에서 배운 것들:
- ✅ 클래스의 탄생과 기본 개념
- ✅ 캡슐화와 접근 제어
- ✅ 멤버 함수와 this 포인터
- ✅ 정적 멤버와 친구 함수
다음 Unit 예고
Unit 11: 생성자와 소멸자
- 다양한 생성자 종류
- 복사 생성자
- 소멸자와 자원 관리
- 이동 생성자 (C++11)
“객체지향 프로그래밍의 세계에 오신 것을 환영합니다! 🚀”
Last updated on