5교시

//
리턴값과레퍼런스이야기

 

// 값을리턴하는함수

// 1) bulit in type 의값을리턴( ex. int foo() )

//      => 리턴값은상수취급된다.

// 2) user type의값을리턴( ex. Point foo() )

//      => 임시객체를리턴한다.( 일부컴파일러는임시객체를상수취급하기도한다.)

int x = 10;

 

int& foo()

{

        return x;

}

 

void main()

{

//      int s = foo();        // 값을리턴하면10 = 30의의미를가진다.

        foo() = 30;           // &을리턴하면된다.

                               

 

         cout << x << endl;

}

 

//================================================

// 1. 함수가레퍼런스를리턴하는이유.

//    (1) built in type의레퍼런스( int& foo() )

//             => "함수호출() = "의표현을가능하게하기위해

//             => 함수호출이lvalue에놓이기위해.

 

//    (2) user type의레퍼런스-> 임시객체의생성을막기위해사용.

//             ex) Point& foo()

 

struct Point

{

        int x;

        int y;

};

Point p = { 1, 2 };

 

Point& foo()

{

        return p;

}

 

void main()

{

        foo().x = 10;          // user type의리턴값은상수가아니다.

 

        cout << p.x << endl;

}

Tag |

7.24(화) C++기초문법 - reference

from Study/C++ 2007/07/24 17:14 view 11636

4교시

//
레퍼런스문법총정리

// 1. 개념: 기존메모리에대한별명.

int main()

{

        int  n = 10;

        int* p = &n;

        int& r = n;            //

 

        r = 20;

 

        cout << n << endl;     // 20

 

        int& r2;               // ? Error. 반드시초기화되어야한다.

        //----------------------------------------------------

        int*& rp = p;  // ok. 포인터의별명

        int&* pr = r;  // 별명의주소?  error

}


 

// 2. 원리: 내부적으로대부분의컴파일러는포인터를사용한다.

//         "자동으로역참조되는포인터" 라고도부른다.

void inc1( int x )     { ++x; }

void inc2( int* p )    { ++(*p); }

void inc3( int& r ) { ++r; }

 

void main()

{

        int a = 10;

        int b = 10;

        int c = 10;

 

        inc1( a );             // 실패- call by value

        inc2( &b );            // ok. call by pointer

        inc3( c );             // ok. call by reference int &r = c;

 

        cout << a << endl;     // 10

        cout << b << endl;     // 11

        cout << c << endl;     // 11

}


 

// 3. 함수호출과레퍼런스

 

// 인자값을변경하는함수-> 포인터가좀더좋다. ( 명확하다. )

// 인자값이바뀌지않은함수

// 1) bulit in type => const T&가오히려나쁘다.(4byte사용, 레지스터사용못함.)
//                     call by value
를사용.

// 2) user type     => const T&


struct AAA

{

        int data[10000000];   // 1M라고가정.

};

 

void foo( const AAA& a )   // call by value :  값을 변경하지 않을것 이다.

{                          // 단점: 메모리 사용량이 2개가 된다.

        a = 20;            // const& : 메모리 사용량을 줄이고 값을 변경하지 않게 한다.

}

 

void main()

{

        AAA x = 10;

 

        foo ( x );

       

        cout << x << endl;

}


 

Tag |

7.24(화) C++ 기초문법 - namespace

from Study/C++ 2007/07/24 16:52 view 12446

3교시

// Namespace
문법에관해서

// 1. 개념

// 프로그램을논리적인구조로구별하기위한문법

// 아울러이름충돌을막을수있다.

// 2. 함수접근방법

//    1. 완전한이름사용

//    2. using 선언(Declaration 사용)

//    3. using 지시어(Directive 사용)


namespace Audio_System

{

        void foo()

        {

               cout << "Audio" << endl;

        }

}

namespace Video_System

{

        void foo()

        {

               cout << "Video" << endl;

        }

}

void main()

{

    Audio_System::foo();

    using Audio_System::foo;


   
using namespace Video_System;
    // using
지시어: namespace 에있는함수모두를이름없이접근할수있다.

 

    foo();

}


// 3. 인자기반탐색( 퀴니크look up )

namespace Graphics

{

        struct Rect

        {

        };

        void Draw( Rect r )

        {

        }

}

 

void main()

{

        Graphics::Rect r;

 

        Draw( r );             // 될까? 자동으로r이속한namespace를검색한다.

        // namespace 를뒤진다.(연산자지정때유용하게사용한다.)

}

 

// 4. namespace 별명(Alias) 과 라이브러리의선택적사용

namespace MathLibray

{

        int plus( int a, int b )

        {

               return 0;

        }

}


//
라이브러리의교체가편해진다.

namespace MathLibray_Ver2

{

        int plus( int a, int b )

        {

               return 0;

        }

}


void
main()

{

        namespace Math = MathLibray_Ver2;     //별명Math로지정해준다.

        Math::plus( 1, 2 );

}



// 5. namespace 함수의외부구현- 클래스보다가벼운이름을묶어놓는공간


namespace AAA

{

        void foo();

}

void AAA::foo()

{

}


// 6. namespace 는열려있다. - 되도록이름을복잡하게만들어라!!

namespace A

{

        void foo() {}

}

 

//다른파일에서or 같은파일에서namespace를추가하게된다.(방지하기위해서는이름!!)

namespace A

{

        void goo() {}

}

 

// 7. namespace std

//#include <iostream.h>       // cout, endl 이전역공간에있다.

#include <iostream>           // cout, endl std라는이름공간에있다.

 

void main()

{

        std::cout << std::endl;

}

 

Tag |

7.24(화) C++ 기초문법 - explicit casting

from Study/C++ 2007/07/24 16:30 view 12514

2교시

// C++ explicit casting
개념

// 1. C의캐스팅은대부분성공한다. 하지만너무나위험하고, 버그가많다.

// 2. C++은용도에따라4가지의casting 연산자가제공된다.

// dynamic_cast : RTTI를위해존재.!! - 상속을알아야한다.

#include <iostream>

using namespace std;

 

int main()

{

        const int c = 10;

        int *p = (int*)&c;

       

        //int* p = static_cast<int*>(&c);
        //
당연히에러.. 말도안되는코드

        //int* p = reinterpret_cast<int*>(&c);
        //const
를벗겨낼수없다. error

        //int* p = const_cast<int*>(&c);
        // ok.
 동일type의객체에대해const속성을제거

        // , 지금처럼const 상수에는사용하지는않는다.const object에사용.


       
*p = 30;

 

        cout << c << endl << *p << endl << &c << endl << p << endl;

}

 

/*

int main()

{

        int a = 0;

        double d = 3.4;

        //int n = d; 
       
//
암시적변환가능. 하지만data의손실이발생한다.

 

        //static_cast : 위험하지않은이성적인변환만허용한다.

        static_cast : 위험하지않은이성적인변환만허용한다

 

        //double *p = (double*)&n;    // 암시적변환은불가능.

                                      // C의명시적변환은가능.

 

        // 결국template 함수의인자를명시적으로지정하고있는모양이다.

        //double* p = static_cast<double*>(&n);      // 허용해줄까? 에러!!

       
double* p = reinterpret_cast<double*>(&n);
        // ok..
대부분성공, C캐스팅과비슷.


       
*p = 100;

}

*/

결론 : static_cast를 사용하여 형변환을 하자!!!

Tag |

7.24(화) C++ 기초문법 - inline

from Study/C++ 2007/07/24 15:41 view 12697

1 교시

1. 함수호출의원리

// 스택을사용하기때문에약간의오버헤드가발생한다.
int square( int a )
{
    return a * a;
}

// C의해결책- 매크로함수- 하지만버그가너무많다.(특히++연산자같은경우)
#define square( x )    ((x)*(x))

// C++의해결책- inline 함수
inline int square( int x )
{
    return x * x;
}

int main()
{
    int n = square(3);     // push 3 인자를스택에넣고 
                                       // call square 함수를호출한다.
    cout << n << endl;
}

2. inline 함수의정확한개념: 호출시해당함수의기계어코드를치환

int square1( int x )
{
    return x * x;
}

inline
int square2( int x )
{
    return x * x;
}

void
main()
{
    int x = 3;
    int a = square1( x );
    int b = square2( x );

    cout << a << ", " << b << endl;

}

inline 치환을 확인하고 싶을 !

cl. acpp /Fas 로 컴파일 하면 a.asm 어셈블리 코드가 생성된다.
inline 치환을 하고 싶다면 /Ob1 이라는 옵션을 추가하면 된다.

inline 은 컴파일 시간에 결정된다. ( 파일단위로 컴파일 하게 된다. )
inline 은 반드시 호출하는 곳과 같은 곳에 있어야 한다.

3. inline 함수와화일크기 
     1. 일반적으로는 커진다.
     2. 하지만 작은 크기의 함수는 오히려 작아진다.

4. inline
과성능. 
     1. 작은
함수는 분명히 빨라진다.(파일크기도 줄어드므로 캐시에 올라올 유리)
       2.
함수는 캐시 적중률(cache hit) 떨어뜨려서 오히려 도가 줄어든다.

5,
inline 함수와헤더파일 ( internal linkage )
       1. inline 함수는 호출하는 파일과 동일 컴파일 단위에 있어야 한다.
     2. 그래서, 헤더 파일에 만들어서 include 해서 사용하는 것이 기본이다.

6. 함수
포인터와 inline
     1. 결국
인라인 함수는 만들때가 아니라 호출할 적용되는 문법이다.

inline void foo ()
{
    cout << "1" << endl;
}

void main()
{
    foo();    // ok. inline 치환된다.     

    void (*f)() = foo;     

    f();    // inline 치환될까? 대부분의컴파일러에서inline 치환이 
            // 되지않을수있다.
}

Tag |

7.23(월) C++ 기초문법

from Study/C++ 2007/07/23 12:01 view 20126

1 교시

Tool : Visual Studio 2005 Express( 컴파일러 cl.exe)
#include <iostream> // 98년 재정된 표준 C++

프로젝트- 속성- 구성속성- C/C++ - 언어 : 언어 확장 사용 안 함
예 : 표준 언어를 사용한다. Cl컴파일러(MS꺼)에서 지원하는 언어 사용안함.
아니오 : MS함수들을 사용한다. atoi, itoa 등등..

Defalut Parameter
1. 마지막 파라미터(오른쪽)부터 차례대로 지정해야 한다.
2. 함수 선언부와 구현부로 나눌 때는 반드시 선언에 지정한다.

오버로딩
A) 리턴값은 영향을 주지 않는다. 단지 인자로만 구분한다.
B) 디폴트 파라미터가 있을때는 주의 해야 한다.
C) 잘못된 overloading은 코드의 방해만 될 뿐이다.
D) 오버로딩 함수를 찾는 순서를 알아두자.
E) 디자인 관점에서의 오버로딩.
   - 동일 함수의 호출이 상황에 다르게 동작한다.
   - 다형성 구현의 가장 기본문법이  오버로딩 !

1. 디자인 측면에서 - 다형성 지원의 기본문법 - 너무 좋은 기능
2. 원리 -> name mangling
3. 주의 -> c/c++ 에서 모두 사용 가능한 헤더 만들기
4. 함수 찾는 순서 - 5단계
 - 1.Exactly Matching :  전달하는 인자와 정확히 일치하는 type이 있는지 찾는다.
 - 2.Promotion : Data의 손실이 없는 방향으로의 변환이 가능한 함수가 있는지 찾는다.
 - 3.Standard Conversion : 표준 Type들간의 암시적인 변환이 발생한 후 함수 호출.
 - 4.User Define Conversion Operator : 사용자가 만든 변환 연산자가 있다면 이것을 사용하여 변환후 함수 호출.
 - 5.'...;을 인자로 갖는 함수 : 가변 파라미터를 갖는 함수는 파라미터의 Type이나 계수에 무관하게 호출.

2교시

a.cpp // C++ main()에서 #include "b.h"(C언어)의 Add() 함수를 호출하기.
b.c   // Add( int a, int b );
b.h

문제점:
error LNK2019: "int __cdecl Add(int,int)" (?Add@@YAHHH@Z)
외부 기호(참조 위치: _main 함수)에서 확인하지 못했습니다.
->C++컴파일러는 함수오버로딩을 위해 함수의 이름을 변환(name mangling)한다.
그러므로 C에서 함수를 불러오게 되면 함수의 이름을 찾지 못하게 된다.

해결책:
extern "C"
C++ 컴파일러에서 C 문법으로 컴파일 해달라는 지시어.
// 이름변환(name mangling)이 발생 하지 않는다.

문제점:
a.cpp를 a.c 로 바꾸게 되면 C에서 지원하지 않는 extern "C"를 사용하지 못한다.
error C2059: 구문 오류 : '문자열'
// 모든 C++ 컴파일러는 __cplusplus 라는 매크로를 내부적으로 정의하고 있다.
해결책:

#ifdef __cplusplus
extern "C" {
#endif

 int Add(int , int);

#ifdef __cplusplus
}
#endif

// 결론 어떤 함수를 만들어서 c/c++에서 모두 사용하려면
// 1. 소스는 .c로 만든다. - 함수이름 변환이 발생되지 않게
// 2. .h는 위의 기법을 적용해서 c/c++모두에서 사용할 수 있게 한다.

3교시

// C에서 함수 1개로 모든 type에 안전하게 동작하는 함수 만들기
//
매크로 함수 : 모든 type에 동작하는 함수 만들때 사용.
//
단점 - 버그가 많다.( 특히, ++이 들어가면
... )
//#define square( x ) ((x) * (x))

// C++의 해결책 - template
//
일반함수 : 값이 전달된다
.
//
함수 template : type과 값이 전달된다.

template<typename T> T square( T a )
{
 return a * a;
}

template<typename T> T Max( T a, T b )
{
 return a < b ? b : a;
}

void main()
{
 cout << Max(1, 2) <<endl;
 cout << Max<int> ( 65, 'B' ) << endl;
 // template
의 명시적

 //
인스턴스화..
 //
명시적으로 type을 전달한다는 의미
.
}

Tag |