icon안동민 개발노트

멤버 함수와 멤버 변수


멤버 변수 (Data Members)

 멤버 변수는 클래스의 상태를 나타내는 변수들입니다. 객체의 속성을 표현하며, 각 객체마다 고유한 값을 가집니다.

 멤버 변수 선언

class Person {
private:
    std::string name;  // 멤버 변수
    int age;           // 멤버 변수
    double height;     // 멤버 변수
public:
    // 멤버 함수들...
};

 멤버 변수 초기화

 멤버 변수는 여러 방법으로 초기화할 수 있습니다.

  1. 생성자 초기화 리스트 (권장)
class Person {
private:
    std::string name;
    int age;
public:
    Person(const std::string& n, int a) : name(n), age(a) {}
};
  1. 클래스 내 직접 초기화 (C++ 11 이후)
class MyClass {
private:
    int x = 0;
    std::string s{"default"};
public:
    MyClass() {}  // x와 s는 위에서 지정한 값으로 초기화됨
};
  1. 생성자 본문 내 초기화
class MyClass {
private:
    int x;
public:
    MyClass() {
        x = 0;  // 비권장: 초기화 리스트보다 덜 효율적일 수 있음
    }
};

멤버 함수 (Member Functions)

 멤버 함수는 클래스의 행동을 정의하는 함수들입니다. 객체의 상태를 조작하거나 정보를 반환하는 역할을 합니다.

 일반 멤버 함수

class Rectangle {
private:
    double width, height;
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    
    double getArea() {
        return width * height;
    }
    
    void scale(double factor) {
        width *= factor;
        height *= factor;
    }
};

 const 멤버 함수

 객체의 상태를 변경하지 않는 함수는 const로 선언해야 합니다. 이는 컴파일러가 최적화를 수행하고 의도치 않은 수정을 방지하는 데 도움을 줍니다.

class Circle {
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    
    double getArea() const {
        return 3.14159 * radius * radius;
    }
    
    double getRadius() const {
        return radius;
    }
};

 정적 멤버 함수

 클래스의 인스턴스 없이 호출할 수 있는 함수입니다. 클래스 전체에 관련된 작업을 수행할 때 유용합니다.

class MathUtils {
public:
    static int add(int a, int b) {
        return a + b;
    }
    
    static double pi() {
        return 3.14159;
    }
};
 
int sum = MathUtils::add(5, 3);  // 객체 생성 없이 호출 가능
double piValue = MathUtils::pi();

this 포인터

 this는 현재 객체를 가리키는 포인터입니다. 멤버 함수 내에서 현재 객체의 멤버에 접근하거나, 객체 자체를 참조할 때 사용됩니다.

class Counter {
private:
    int count;
public:
    Counter(int c = 0) : count(c) {}
    
    Counter& increment() {
        ++count;
        return *this;  // 현재 객체 반환
    }
    
    void resetToValue(int value) {
        this->count = value;  // 'this->' 사용으로 멤버 변수임을 명확히 함
    }
};
 
Counter c;
c.increment().increment();  // 메서드 체이닝

인라인 함수

 inline 키워드를 사용하거나 클래스 정의 내에 함수를 정의하여 인라인 함수를 만들 수 있습니다. 인라인 함수는 컴파일러에 의해 호출 지점에 직접 삽입되어 함수 호출 오버헤드를 줄일 수 있습니다.

class Point {
private:
    int x, y;
public:
    Point(int x = 0, int y = 0) : x(x), y(y) {}
    
    inline int getX() const { return x; }
    inline int getY() const { return y; }
    
    // 클래스 내 정의된 함수는 자동으로 인라인 후보가 됩니다
    int manhattanDistanceTo(const Point& other) const {
        return std::abs(x - other.x) + std::abs(y - other.y);
    }
};

멤버 함수 포인터

 멤버 함수를 가리키는 포인터를 사용할 수 있습니다. 이는 런타임에 특정 멤버 함수를 선택하여 호출해야 할 때 유용합니다.

class MyClass {
public:
    void foo() { std::cout << "foo" << std::endl; }
    void bar() { std::cout << "bar" << std::endl; }
};
 
int main() {
    void (MyClass::*ptr)() = &MyClass::foo;
    MyClass obj;
    (obj.*ptr)();  // "foo" 출력
    
    ptr = &MyClass::bar;
    (obj.*ptr)();  // "bar" 출력
    
    return 0;
}

실습 : 은행 계좌 관리 시스템

 다음 요구사항을 만족하는 BankAccountBank 클래스를 구현해보세요.

  • BankAccount 클래스 : 계좌번호, 소유자 이름, 잔액을 멤버 변수로 가짐
  • Bank 클래스 : 여러 BankAccount 객체를 관리하고, 계좌 생성, 입금, 출금, 송금 기능을 제공
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
 
class BankAccount {
private:
    std::string accountNumber;
    std::string ownerName;
    double balance;
 
public:
    BankAccount(const std::string& number, const std::string& name, double initialBalance = 0.0)
        : accountNumber(number), ownerName(name), balance(initialBalance) {}
 
    std::string getAccountNumber() const { return accountNumber; }
    std::string getOwnerName() const { return ownerName; }
    double getBalance() const { return balance; }
 
    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            std::cout << "Deposited $" << amount << " to account " << accountNumber << std::endl;
        }
    }
 
    bool withdraw(double amount) {
        if (amount > 0 && balance >= amount) {
            balance -= amount;
            std::cout << "Withdrawn $" << amount << " from account " << accountNumber << std::endl;
            return true;
        }
        std::cout << "Insufficient funds in account " << accountNumber << std::endl;
        return false;
    }
 
    void display() const {
        std::cout << "Account: " << accountNumber << ", Owner: " << ownerName
                  << ", Balance: $" << balance << std::endl;
    }
};
 
class Bank {
private:
    std::vector<BankAccount> accounts;
 
public:
    void createAccount(const std::string& number, const std::string& name, double initialBalance = 0.0) {
        accounts.emplace_back(number, name, initialBalance);
        std::cout << "Account created successfully." << std::endl;
    }
 
    BankAccount* findAccount(const std::string& number) {
        auto it = std::find_if(accounts.begin(), accounts.end(),
                               [&number](const BankAccount& acc) { return acc.getAccountNumber() == number; });
        return (it != accounts.end()) ? &(*it) : nullptr;
    }
 
    void deposit(const std::string& number, double amount) {
        if (auto account = findAccount(number)) {
            account->deposit(amount);
        } else {
            std::cout << "Account not found." << std::endl;
        }
    }
 
    void withdraw(const std::string& number, double amount) {
        if (auto account = findAccount(number)) {
            account->withdraw(amount);
        } else {
            std::cout << "Account not found." << std::endl;
        }
    }
 
    void transfer(const std::string& fromNumber, const std::string& toNumber, double amount) {
        auto fromAccount = findAccount(fromNumber);
        auto toAccount = findAccount(toNumber);
 
        if (fromAccount && toAccount) {
            if (fromAccount->withdraw(amount)) {
                toAccount->deposit(amount);
                std::cout << "Transfer successful." << std::endl;
            }
        } else {
            std::cout << "One or both accounts not found." << std::endl;
        }
    }
 
    void displayAllAccounts() const {
        for (const auto& account : accounts) {
            account.display();
        }
    }
};
 
int main() {
    Bank bank;
 
    bank.createAccount("1001", "Alice", 1000);
    bank.createAccount("1002", "Bob", 500);
 
    std::cout << "\nInitial account status:" << std::endl;
    bank.displayAllAccounts();
 
    bank.deposit("1001", 200);
    bank.withdraw("1002", 100);
    bank.transfer("1001", "1002", 300);
 
    std::cout << "\nFinal account status:" << std::endl;
    bank.displayAllAccounts();
 
    return 0;
}

연습 문제

  1. Time 클래스를 구현하세요. 시, 분, 초를 멤버 변수로 가지고, 시간 더하기, 빼기 연산을 수행하는 멤버 함수를 구현하세요.
  2. Matrix 클래스를 구현하세요. 2차원 배열을 동적으로 할당하여 행렬을 표현하고, 행렬 덧셈, 뺄셈, 곱셈을 수행하는 멤버 함수를 구현하세요.


참고 자료

  • Stroustrup, Bjarne. "The C++ Programming Language (4th Edition)"
  • Meyers, Scott. "Effective C++: 55 Specific Ways to Improve Your Programs and Designs"
  • Sutter, Herb and Alexandrescu, Andrei. "C++ Coding Standards : 101 Rules, Guidelines, and Best Practices"
  • C++ Reference : Member functions
  • ISO C++ Core Guidelines : F : Functions