본문 바로가기

Programming/C Programming

c 와 c++ 의 const 내용정리

학생때 쓴 강좌인데 필요로 하시는 분들이 계시내요.

참고 하세요.




아래 static부분이 어서 const 정리 내용입니다.

 

순서는 다음과 같습니다.

 

1. const

2. 배열과 const

3. const와 Intenal Linkage

4. 포인터의 const

5. const 함수

6. const 멤버변수

7. const 멤버함수

8. 함수의 파라미터를 (const &)로 쓰자!

 

빼먹은 부분없이 정리해 볼려고 했는데.. 잘 되었는지는 모르겠내요.

읽어보시고 틀린곳이나 추가할 부분은 지적해 주세요.

많은 도움되길 바랍니다. ^^

 

 

=========================================<const>======================================

과거에 상수를 정의할때는 메크로를 썻다

#define PI 3.14

이렇게 메크로를 쓰면 우리는 PI를 변수처럼 사용할 수 있으며 값도 바꿀수 없는
상수로 만들 수가 있었다.

하지만 이렇게 전처리계를 사용하면, ERROR를 찾을 수가 없는 단점이 있다.
이런 연유로 const가 생기게 되었다고 한다.

const double PI = 3.14;

같이 쓰며 상수를 나타낸다.

 

==================================<배열과 const>====================================

int a[b];형식으로 최초 배열을 선언할때
b는 상수여야한다.

-----------------------------------------------------------------------------------

int b=10;
const int c=10;

int a[b]; // ERROR
int a[c]; // OK

-----------------------------------------------------------------------------------

그렇다면 다음은 어떨까?

-----------------------------------------------------------------------------------

const int s[3]={1, 2, 3};

int c[ s[2] ];   // ???

-----------------------------------------------------------------------------------

분명 s[3]에 저장된 값들은 각각 상수들이다.
값을 바꿀 수도 없다.
하지만 ???부분은 ERROR를 낸다.
이유는 컴파일시 데이터를 메모리에서 읽어와야 하기때문이다.

 

 

==============================<const와 Intenal Linkage>==============================


--------------------A.cpp--------------------------
int x=0;
const int y=1;  // const는 Intenal Linkage를 가진다.


--------------------B.cpp--------------------------

#include <iostream>
using namespace std;

extern int x;
//extern int y; // ERROR

void main()
{
 cout << x << endl;
}

-----------------------------------------------------------------------------------

const변수는 기본적으로 Intenal Linkage를 가진다.

 

===================================<포인터의 const>=================================

#include <iostream>
using namespace std;

void main()
{
 int a = 0;
 int b = 1;

 const int *p = &a;    // 1번
 //(*p) = 3;
 p = &b;
 
 int * const q = &a;   // 2번
 (*q) = 3;
 //q = &b;

 const int c = 2;      // 3번
 const int *k = &c;
 //int *t = &c;

}

-----------------------------------------------------------------------------------

*을 중심으로 앞쪽에 const가 있으면 데이터에 관한 상수(1번),
뒤쪽에 const가 있다면 주소에 관한 상수이다(2번).

각각의 포인터를 만든후에 데이터를 변경하는 일과, 주소를 변경하는 모습을 보여준다.
주석으로 막은 부분은 ERROR가 나는 부분이다.

3번을 보면 알 수 있겠지만 const 변수의 포인터는 const 포인터 이여야 한다.

 


===================================<const 함수>=====================================

#include <iostream>
using namespace std;

const int foo(int a) // 1번
{
 cout << "const int foo()" << endl;
 return ++a;
}

int const goo(int b) // 2번
{
 cout << "int const goo()" << endl;
 return ++b;
}

int hoo(const int c) // 3번
{
 cout << "int const goo()" << endl;
 //return ++c; // ERROR
 return c;
}

//int hoo(int c) {return c++;} // ※일반함수는 const파라미터 오버로딩을 지원하지 않는다.

//int koo(int a) const{} // ※일반함수는 이러한 형식을 사용할 수 없다.


void main()
{
 int i=3;

 cout << foo(i) << endl;
 cout << goo(i) << endl;
 cout << hoo(i) << endl;
}

-----------------------------------------------------------------------------------

1, 2번의 형태는 일반함수에게 아무런 영향도 주지 못한다.
const가 붙었다고 해도 함수는 자신내부의 값을 바꾸며 단순히 리턴한다.
일반함수에서 변수를 보호하는 방법은 3번의 형식이다.
※표한 두가지 함수를 눈여겨 보자.
일반함수에서는 사용할 수 없지만, 이는 멤버함수에서 허용된다.

 


===============================<const 멤버변수>=====================================


#include <iostream>
using namespace std;

class A
{
public:
 A():y(0){}
 int x;
 const int y;
};

void main()
{
 A a;
 a.x = 3;
 //a.y = 2;
}


-----------------------------------------------------------------------------------

const 멤버변수는 클래스 초기화시 꼭 초기화를 해 주어야만 하며
그 방식도 A():y(0){} 이러한 방식을 써야한다.
A(){y=0;}으로 초기화 해주면 대입이 되어 ERROR이 나게 된다.

 

 


====================================<const 멤버함수>================================

#include <iostream>
using namespace std;

class A
{
public:
 A():x(0){}

 const int foo() {cout << "const int foo() : "; return ++x;} // 1번
 int const hoo() {cout << "int const hoo() : "; return ++x;} // 2번
 int koo() const {cout << "int koo() const : "; return x;} // 3번
 int goo(); // 4번
 int goo() const; // 5번

private:
 int x;
};

int A::goo()
{
 cout << "int goo() : ";
 return ++x;
}

int A::goo() const
{
 cout << "int goo() const : ";
 return x;
}

void main()
{
 A a;
 cout << a.foo() << endl;
 cout << a.hoo() << endl;
 cout << a.koo() << endl;
 cout << a.goo() << endl;

 cout << endl << "const 객체 생성" << endl;

 const A b;

 //cout << b.foo() << endl;
 cout << b.goo() << endl;
 cout << b.koo() << endl;
}

-----------------------------------------------------------------------------------

조금은 복잡한 소스이다. 하지만 잘 살펴보면 재미있는것을 발견할 수 있을것이다.

1, 2번의 방식은 아무영향도 줄 수 없다. 이는 일반함수에서의 경우와 동일하다.
결국 함수의 리턴값 앞,뒤에 쓰는 const는 별 영향력이 없다.

3번 koo는 int koo() const형식으로 정의되었고 이는 내부에서 맴버변수가 const임을 보여준다.

const형태로 정의되어 있는 koo를 일반객체 a로 호출했을때에도 호출이 가능하며,
반대로 const객체 b에서는 const멤버함수가 아닌 foo(), hoo()는 호출할 수 없다.
즉, const객체에서는 const멤버함수만을 부를 수 있다.

마지막 goo는 4번 일반형태와 5번 const형태 두가지가 있다.
C++은 const멤버함수에 대해 오버로딩을 지원한다.
일반객체에서 a.goo를 호출했을때는 int goo()가 호출되며
const객체에서 b.goo()를 호출했을때는 int goo() const가 호출된다.

 

 


========================<함수의 파라미터를 (const &)로 쓰자!>==========================


1. 첫번째 이유

파라미터로 &을 쓰면, 저장공간을 새로 잡지 않기때문에 매모리 관리 측면에서
유리하다는건 쉽게 알 수 있을것이다.
이때 다음을 보자

-----------------------------------------------------------------------------------

#include <iostream>
using namespace std;

void foo(int &a)
{}

void main()
{
 int a = 10;
 const int b = 5;

 foo(a);
 foo(b); // ERROR
}

-----------------------------------------------------------------------------------

이때 const int b;는 함수 파라미터가 const형으로 된 함수에서만 읽을 수 있다.
또한 int a;역시 const형으로 된 함수에서 읽을 수 있다. 그러므로

void foo(const &a)
{}

로 해준다면 두 형태를 하나의 함수로 모두 받을 수 있다.

 

2. 두번째 이유

-----------------------------------------------------------------------------------

void foo(int b)
{}

void goo(int &b)
{}

void hoo(const &b)
{}

void main()
{
 double a = 10;

 foo(a);  // 1번
 goo(a);  // 2번
 hoo(a);  // 3번
}

-----------------------------------------------------------------------------------

1번 : a가 b로 형변환이 일어나면서 가능하다.
2번 : b는 단지 a의 참조자일 뿐이다. double를 int형 참조자로 받는것은 ERROR다.
3번 : const형일때는 임시로 int 저장장소를 만들고 double의 정수값만을 받아서
      형변환을 허용한다.

 

3. 세번째 이유

-----------------------------------------------------------------------------------

#include <iostream>
using namespace std;

class A
{
 
public:
 A(){cout << "생성자" << endl;}
 A(const A& ){cout << "복사생성자" << endl;}
 ~A(){cout << "소멸자" << endl;}
};

foo(A b){}

goo(const A& c){}

void main()
{
 A a;

 cout << " ==객체 파라미터== " << endl;
 foo(a);

 cout << " ==const & 파라미터== " << endl;
 goo(a);
}

-----------------------------------------------------------------------------------

-출력-

생성자
 ==객체 파라미터==
복사생성자
소멸자
 ==const & 파라미터==
소멸자


foo함수는 객체로 class A의 객체를 받고 있으며,
goo함수는 const &로 A의 객체를 받고있다.

이때 foo같이 객체로 받으면 함수는 복사생성자를 이용해서
임시객체를 만들고 그것을 foo함수 안에 전달하게 된다.

하지만 const & 파라미터를 사용하면, 임시객체가 만들어지지 않게된다.

'Programming > C Programming' 카테고리의 다른 글

The cost of inline functions  (0) 2010.12.21
배열 초기화 선언  (1) 2010.10.29
c 와 c++ 의 static 내용정리  (0) 2010.10.08
해킹방지를 위한 코딩법  (0) 2010.08.20
__read_mostly keyword  (0) 2010.06.29