static member data
-
static 멤버 변수 모양
-
클래스 안에 선언(declaration) -> static 키워드 사용
-
클래스 외부에 정의(definition) -> static 키워드 사용 안함
-
-
static 멤버 변수
-
모든 객체가 공유(전역 변수와 유사)
-
접근 지정자 사용 가능
- 객체를 생성하지 않아도 메모리에 존재(전역)
- 객체 생성시 static 멤버는 객체 메모리에 불포함(sizeof 객체로 해보면 static 멤버 제외 사이즈가 리턴)
- "클래스 이름::변수 이름" 사용으로 클래스별 동일 이름 사용 가능
-
- static 멤버 접근 방법
- 클래스이름::멤버이름 : Car::cnt // 권장
- 객체이름::멤버이름 : c1.cnt // 일반 멤버인지 static 멤버인지 구분 모호
class Car
{
int speed;
public:
static int cnt; // 선언(Declaration)
Car() { ++cnt; }
~Car() { --cnt; }
};
int Car::cnt = 0; // 정의(Definition)
int main()
{
// 1. 객체 없이도 메모리에 존재
std::cout << Car::cnt << std::endl;
// 2. 객체 메모리에 포함되지 않음
Car c1, c2;
std::cout << Car::cnt << std::endl; // 3. 접근 방법(클래스::멤버이름)
std::cout << c1.cnt << std::endl; // 3. 접근 방법(객체.멤버이름)
}
static member function
-
static 멤버 함수
-
객체 없이 호출 가능한 멤버 함수
-
클래스이름::함수이름()으로 호출 가능
-
객체이름.함수이름()으로도 호출 가능
-
일반 멤버 함수 : 호출하려면 반드시 객체가 필요
-
class Car
{
int speed;
public:
static int cnt; // 선언(Declaration)
Car() { ++cnt; }
~Car() { --cnt; }
static int getCount() { return cnt; }
};
int Car::cnt = 0; // 정의(Definition)
int main()
{
// 객체 생성과 무관하게 호출 가능(클래스::함수이름)
std::cout << Car::getCount() << std::endl;
Car c1, c2;
// 객체를 통해서도 호출 가능(객체.함수이름)
std::cout << c1.getCount() << std::endl;
}
-
static 멤버 함수 특징
-
일반 멤버 data에 접근 불가
-
static 멤버 데이터만 접근 가능
-
선언과 구현으로 분리할때 선언에만 static 표기
-
class Test
{
int data1;
static int data2; // 선언부에는 static 표기
public:
static void f2()
{
data1 = 0; // 일반 멤버 data1에 접근 불가(컴파일 에러)
data2 = 0; // static 멤버 data2에 접근 가능
}
static void f3(); // 선언부에는 static 표기
};
void Test::f3() // 구현부 분리시 static 표기 안함
{
}
const member function
-
상수 멤버 함수(const member function) 특징
-
상수 멤버 함수 안에서는 모든 멤버를 상수 취급
-
멤버의 값을 변경할 수 없음
-
상수 멤버 함수 안에서는 상수 멤버 함수만 호출 가능
- 상수 멤버 함수와 비상수 멤버 함수를 동일한 이름으로 제공 가능
-
class Point
{
public:
int x, y;
Point(int a, int b) : x(a), y(b) {}
void set(int a, int b)
{
x = a;
y = b;
}
void getX() const { return x; }
void getY() const { return y; }
void print() const // 상수 멤버 함수
{
getX() // const 멤버 함수 호출(OK)
x = 10; // 멤버 데이터 변경(Error)
set(1, 2); // 일반 멤버 함수 호출(Error)
std::cout << x << ", " << y << std::endl; // 멤버 데이터 읽기(OK)
}
};
int main()
{
Point p(1, 2);
p.x = 10;
p.set(10, 10);
p.print();
}
-
상수 멤버 함수(const member function) 필요성
-
상수 객체는 상수 멤버 함수만 호출할 수 있음
-
객체의 상태를 변경하지 않는 모든 멤버 함수는 상수 함수가 되어야 함
-
getter 대부분 상수 멤버 함수가 되어야 함
-
class Point
{
public:
int x, y;
Point(int a, int b) : x(a), y(b) {}
void set(int a, int b)
{
x = a;
y = b;
}
void print() const; // 구현부를 분리시 선언, 구현부 모두 const 표시
};
void Point::print() const // 구현부를 분리시 선언, 구현부 모두 const 표시
{
std::cout << x << ", " << y << std::endl;
}
// 자주쓰는 패턴
void foo(const Point& p)
{
// p의 멤버함수가 상수 멤버함수로 제공되지 않는다면 호출 가능한 멤버가 없음
}
int main()
{
const Point p(1, 2);
p.print(); // 상수객체는 상수 멤버 함수만 호출 가능(const가 아닐경우 error)
}
- mutable
- 상수 멤버 함수 안에서 값을 변경 하고 싶을때
- 논리적으로는 상수 멤버 함수지만 다양한 이유로 멤버의 값을 변경하고 싶을때
class Point
{
public:
int x, y;
int data = 0;
mutable int fooCount = 0;
const int* getPointer() const { return &data; }
void foo() // 동일 이름의 상수 멤버 함수, 비상수 멤버 함수를 동시에 제공 가능
{
std::cout << "foo()" << std::endl;
}
void foo() const // 동일 이름의 상수 멤버 함수, 비상수 멤버 함수를 동시에 제공 가능
{
fooCount++; // 상수 멤버 함수에서 특별한 이유로 값 변경 필요시 mutable 지시자 선언
std::cout << "foo() const" << std::endl;
}
};
int main()
{
Point p1;
p1.foo(); // 1. 비상수 함수 호출, 2. 없을 경우 상수 함수 호출
}
this pointer
-
내부 원리
-
멤버 함수 호출 시 내부적으로 객체의 주소가 this라는 이름으로 전달됨
-
class Point
{
int x = 0;
int y = 0;
public:
void set(int a, int b)
{
std::cout << this << std::endl; // main의 p1, p2 객체 주소랑 this는 동일 값
}
};
int main()
{
Point p1;
Point p2;
std::cout << &p1 << std::endl;
p1.set(10, 20); // 내부적으로는 멤버 함수는 호출 시 객체의 주소가 추가로 전달됨
std::cout << &p2 << std::endl;
p2.set(10, 20); // 내부적으로는 멤버 함수는 호출 시 객체의 주소가 추가로 전달됨
}
-
멤버의 이름과 지역변수(함수 인자)이름이 동일할때
-
지역 변수가 우선시 됨
-
this를 사용하면 멤버 변수에 접근 가능
-
class Point
{
int x = 0;
int y = 0;
public:
void set(int x, int y)
{
this->x = x; // 동일 변수명 사용시 지역변수 우선이지만 명시적인 구분을 위해 this 활용 가능
this->y = y;
}
};
int main()
{
Point p1;
p1.set(10, 20);
}
-
this를 리턴하는 함수
-
멤버 함수 호출을 연속적으로 사용할수 있음
-
자신(*this)을 리턴시 반드시 참조로 리턴 해야 함(return by reference 참조)
-
class Point
{
int x = 0;
int y = 0;
public:
void set(int a, int b)
{
this->x = a;
this->y = b;
}
Point* foo() { return this; } // this 이용 포인터 리턴
Point& goo() { return *this; } // this 이용 값에 대한 레퍼런스 리턴
//Point goo() { return *this; } // this 이용 값으로 바로 리턴시 임시 객체가 계속 복사됨 주의!
};
int main()
{
Point p1;
p1.foo()->foo()->foo(); // 포인터 재호출
t.goo().goo().goo(); // 값 재호출
}
- this 주의 사항
- static 멤버 함수 안에서는 this를 사용 불가
- static 멤버 함수 안에서는 this 사용이 불가하므로 멤버 데이터 접근이 불가능함
class Test
{
int data;
public:
static void foo()
{
std::cout << this << std::endl; // static 멤버 함수 내부에서는 this 사용 불가 Error
data = 0; // this->data = 0; this 없어서 static 멤버 함수에서 일반 멤버 접근이 불가 Error
}
};
int main()
{
Test::foo(); // static 멤버 함수 호출(내부 this 객체 없음)
}
'프로그래밍 언어 > C++' 카테고리의 다른 글
C++ 연산자 재정의 - cout, endl 원리 (2) | 2019.05.08 |
---|---|
C++ 연산자 재정의 - 기본 개념 (0) | 2019.05.08 |
C++ 복사 생성자 (0) | 2019.05.06 |
C++ 접근 지정자, 생성자, 소멸자 (0) | 2019.05.06 |
C++ OOP(Object Oriented Programming) (0) | 2019.05.06 |