// 멤버함수의호출원리

class A

{

        int x;

public:

        void foo( int a )      // void foo( Point* const this, int a)

        {

               x = a;                 // this->x = a;

        }

};

 

void main()

{

        A a1, a2;

        a1.foo(10);  // foo( &a1, 10 );

        // push &a1 이 아니라 mov ecx, &a1
        // a1 , 즉 this
에 대한 인자는 레지스터로 보낸다.( thiscall )

        // push 10

        // call foo

}

Tag |

// 싱글톤 : 객체가 하나만 생성되게 한다.


// Mayer
singleton( stack 이용 )

class MouseCursor

{

private:

        MouseCursor() {}

public:

        static MouseCursor& GetInstance()

        {

               static MouseCursor m;

               return m;

        }

};

 

void main()

{

        MouseCursor& m1 = MouseCursor::GetInstance();

        MouseCursor& m2 = MouseCursor::GetInstance();

}

//heap 공간에singleton 구현하기

#include <iostream>

using namespace std;

 

class Singleton

{

private:

        static Singleton* m_cursor;

        Singleton() {}

        Singleton(const Singleton&);

        ~Singleton()

        {

               if ( m_cursor != NULL )

               {

                       delete m_cursor;

               }

        } 

 

public:

        static Singleton* GetInstance()

        {

               if (m_cursor == NULL)

                       m_cursor = new Singleton();

               return m_cursor;

        }

};

 

Singleton* Singleton::m_cursor = NULL;

 

void main()

{

        Singleton* single1 = Singleton::GetInstance();

        Singleton* single2 = Singleton::GetInstance();

}


// Double Checked Locking Singleton( 윈도우- 멀티스레드환경대비)

// 객체를 생성할 때 CRITICAL_SECTION 으로 감싸준다.
#include
<iostream>

#include <windows.h>

using namespace std;

 

class CriticalSection

{

private:

        CRITICAL_SECTION cs;

public:

        CriticalSection() { InitializeCriticalSection(&cs); }

        ~CriticalSection() { DeleteCriticalSection(&cs); }

 

        void Enter()

        {

               EnterCriticalSection(&cs);

        }

        void Leave()

        {

               LeaveCriticalSection(&cs);

        }

};

 

CriticalSection g_cs;

 

class Singleton

{

private:

        static Singleton* m_cursor;

       

        Singleton() {}

        Singleton(const Singleton&);

        ~Singleton()

        {

               if ( m_cursor != NULL )

               {

                       delete m_cursor;

               }

        } 

 

public:

        static Singleton* GetInstance()

        {

               if (m_cursor == NULL)

               {

                       m_cursor = new Singleton();

               }

               return m_cursor;

        }

};

 

Singleton* Singleton::m_cursor = NULL;

 

DWORD WINAPI SingletonProc(void* pv)

{

        Singleton* pSingle = NULL;

 

        while (1)

        {

               if (pSingle == NULL)

               {

                       g_cs.Enter();

                       pSingle = Singleton::GetInstance();

                       cout << "Singleton create : " << pSingle << endl;

                       g_cs.Leave();

               }

               Sleep(0);

        }

        return 0;

}

 

void main()

{

        HANDLE hThread[2];

 

        hThread[0] = CreateThread( NULL, 0, SingletonProc, NULL, 0, NULL );

        hThread[1] = CreateThread( NULL, 0, SingletonProc, NULL, 0, NULL );

 

        WaitForMultipleObjects(2, hThread, TRUE, INFINITE);

        CloseHandle(hThread[0]);

        CloseHandle(hThread[1]);

}

Tag |

7.26(목) C++ 기초문법 - static 멤버

from Study/C++ 2007/07/28 23:53 view 16858

// 1. static 멤버data의특징: 모든객체가공유. 객체가없어도메모리에있다.

// 2. static 멤버함수의특징객체가없어도호출가능.

// 3. static 멤버에서는static 멤버만접근가능.

class Point

{

        int x;

        static int y;

 

public:

        void foo()

        {

               x = 10  // 1

               y = 10; // 2

        }

        static void goo()

        {

               cout << this << endl;  // error

               foo();  // error

               x = 10; // error

               y = 10; // 4

        }

};

 

int Point::y = 0;

 

void main()

{


        //클래스 내의 static 멤버 호출 시 1번으로 한다.
       
Point::goo();  // 1
일반함수인지static 함수인지를알수있다.

 

        Point p;

        p.goo();      // 2

}

 

Tag |

// 클래스가내부적으로포인터를가지면소멸자에delete 하라.!

 

// 1. 얕은복사(Shallow Copy) 현상. 해결책3가지.

//             (A). 깊은복사(Deep Copy)

//             (B). 복사를금지한다. - private에선언만제공한다.

//             (C). Referece Counting - 속도가조금빨라진다.
//               (
멀리스레드에서는오히려속도가느려진다. 동기화)



http://www.research.att.com/~bs/string_example.c
 // 창시자 코드!!

#include <iostream>

using namespace std;

 

class String

{

//////////////////////////////////////////////////////////////////////////

        struct SRep // 내포클래스: String에서만이클래스를사용하므로내부에넣어버리자!!

        {

               char* buff;

               int sz;

               int ref;

 

               SRep(int nsz, const char* pbuff)

               {

                       ref = 1;

                       sz = nsz;

                       buff = new char[sz+1]; // add space for terminator

                       strcpy( buff, pbuff );

               }

 

               SRep( const char* s ) : ref(1)

               {

                       sz = strlen(s);

                       buff = new char[sz+1];

                       strcpy( buff, s );

               }

               ~SRep() { delete[] buff; }

 

               SRep* get_own_copy()

               {

                       if ( ref == 1 ) return this;

                       ref--; 

                       return new SRep( sz , buff );

               }

 

               void assign(int nsz, const char* pbuff)

               {

                       if (sz != nsz) {

                              delete[] buff;

                              sz = nsz;

                              buff = new char[sz+1];

                       }

                       strcpy( buff ,pbuff );

               }

        private:

               SRep(const SRep&);

               SRep& operator=(const SRep&);

 

        };     
//////////////////////////////////////////////////////////////////////////

        class Cref

        {

               friend class String;

               String& s;

               int i;

 

               Cref(String& _s, int _i) : s(_s), i(_i) { }

               Cref(const Cref& r) : s(r.s), i(r.i) { }

               Cref();                // not defined, never used

 

        public:

               operator char() const

                {

                       s.check(i); return s.read(i);

                }

               void operator=(char c)

                {

                        s.write(i,c);

                }

 

        };
//////////////////////////////////////////////////////////////////////////

        SRep* rep;

 

public:

       

        class Range {};

 

        String()

        {

               rep = new SRep(0,"");

        }

 

        String( const char* s ) { rep = new SRep(s); }

 

        ~String() { if( --(rep->ref) == 0 ) delete rep; }

 

        // 참조개수기반의복사생성자

        String( const String& s )

        {

               rep = s.rep;

 

               ++(rep->ref);

        }

 

//////////////////////////////////////////////////////////////////////////

        // 참조개수기반의대입연산자

        String& operator=( const String& s )

        {

               // 모든대입연산자의기본은1번째줄에서자신과의참조를비교해야한다.

                if( &s == this ) return *this;

 

               if( --(rep->ref) == 0 ) delete rep;

 

               rep = s.rep;

 

               // 이제count 증가.

               ++(rep->ref);

 

               return *this;

        }

 

        friend ostream& operator<<( ostream& os, const String& s)

        {

               return os << s.rep->buff;

        }

 

        char operator[](int i) const

        {

               check(i);

               return rep->buff[i];

        }

        Cref String::operator[](int i)

        {

               check(i);

               return Cref(*this,i);

        }

 

        String& operator=(const char* s)

        {

               if (rep->ref == 1)

                       rep->assign(strlen(s),s);

               else {

                       rep->ref--;

                       rep = new SRep(strlen(s),s);

               }

               return *this;

        }

//////////////////////////////////////////////////////////////////////////

 

        void check(int i) const

        {

               if (i<0 || rep->sz<=i) throw Range();

        }

 

        char read(int i) const

        {

               return rep->buff[i];

        }

 

        void write(int i, char c)

        {

               rep=rep->get_own_copy();

               rep->buff[i] = c;

        }

};

 

void main()

{

        String s1 = "hello";

        String s2 = s1;

 

        char c = s1[1];               // s1.operator[](1)

        cout << c << endl;     // 'e'가나오면된다.

 

        s1[1] = 'A';           // s1, s2는서로다른"hello" 메모리를사용해야한다.

        cout << s1 << endl;    // "hAllo"

        cout << s2 << endl;    // "hello"

}

 

Tag |

7.25(수) C++ 기초문법 - 복사생성자

from Study/C++ 2007/07/27 00:09 view 15830

#include <iostream>

using namespace std;

 

// 복사생성자개념

// 1. 복사생성자의모양

// 2. 사용자가만들지않으면컴파일러가만들어준다.( 멤버복사를수행한다. )

// 3. 복사생성자는언제호출되는가?

//             (1) 자신의type으로초기화될때Point p2(p1);

//             (2) 함수호출시call by value - const& 로막을수있다.

//             (3) 함수가객체를값으로리턴할때.!!

 

//(3)

class Point

{

public:

        Point()                               { cout << "생성자" << endl; }

        Point( int a, int b )  { cout << "생성자" << endl; }

        ~Point()                              { cout << "소멸자" << endl; }

        Point( const Point& p1 ){ cout << "복사생성자" << endl; }

};

 

Point foo()            //Point p = p1;

{

        //Point p1(1, 2);

        //cout << "foo" << endl;

        //return p1;

 

        cout << "foo" << endl;

 

        // 리턴용도로만사용한다면만들면서리턴해라...

        // 리턴용이름없는객체만만들어진다.

        // Return Value Optimization..!!( RVO )

        return Point(1, 2);           // 생성자를사용해서리턴용객체만만든다.

}

 

void main()

{

        cout << "start" << endl;

        Point p1;

        {

               cout << "in block" << endl;

               foo();

               cout << "out block" << endl;

        }

        cout << "end" << endl;

}

 

/*

class Point

{

public:

        Point()                               { cout << "생성자" << endl; }

        Point( int a, int b )  { cout << "생성자" << endl; }

        ~Point()                              { cout << "소멸자" << endl; }

        Point( const Point& p1 ){ cout << "복사생성자" << endl; }

};

 

 

void foo( Point p )           //Point p = p1;

{

        cout << "foo" << endl;

}

 

void main()

{

        cout << "start" << endl;

        Point p1;

        {

               cout << "in block" << endl;

               foo( p1 );

               cout << "out block" << endl;

        }

        cout << "end" << endl;

}

*/

 

/*

class Point

{

public:

        int x;

        int y;

 

        Point( int a = 0, int b = 0 ) : x(a), y(b) {}

 

        // 복사생성자: 사용자가만들지않으면컴파일러가만들어준다.

        // 기본적으로멤버복사를수행한다.

        Point( const &Point p )

        {

               x = p.x;

               y = p.y;

        }

};

 

void main()

{

        Point p1;

        Point p2(1, 2);

        Point p3(p2);          // Point( Point );

 

        cout << p3.x << endl;

        cout << p3.y << endl;

 

        Point p4 = p3;         // Point p4(p3);       복사생성자호출

 

        int a = 0;

        int a(0);

}

*/

Tag |

#include <iostream>

using namespace std;

 

// 초기화리스트이야기..( Member Initialize List )

// 1. 초기화리스트모양. 특징( 대입이아닌진짜초기화이다. )

// 2. 멤버가놓여있는순서대로초기화한다.

// 3. 상수멤버와레퍼런스멤버는반드시초기화리스트로초기화해야한다.

// 4. 기본생성자가없는클래스를멤버로가질떄반드시초기화리스트를사용해서초기화해야한다.

 

class Point

{

        int x;

        int y;

public:

        Point( int a, int b ) : x(a), y(b)

        {

        }

};

 

class Rect

{

        Point p1;

        Point p2;

public:

        Rect() : p1(0, 0), p2(0, 0)

        {}

};

 

void main()

{

        Rect r;

 

        //Point p1;                   // error. 기본생성자가없다.

        Point p2( 1, 2 );      // Ok. 인자2개생성자는있다.

}

 

/*

class Point

{

public:

        int x;

        int y;

 

        const int c1;

 

//      int c = 0;     //error 아직c가메모리에있는게아니다.

                              // 객체를만들어야c는메모리에있다.

 

public:

        Point() : x(0), y(0), c1(0)           // 초기화

        {

               //x = 0;       // 대입

               //y = 0;

        }

};

 

void main()

{

//      const int c;   // error 초기값이필요.

 

 

        Point p;

        // y(10), x(y)로초기화리스트작성시undefined 대부분쓰레기값

        cout << p.x << endl;
        cout << p.y << endl;   // 10

 

        int a;  // a가객체라면생성자호출

        a = 0;  // 대입연산자가호출.

 

        int b = 0;     // 초기화. 생성자만1번호출된다.

}

*/

Tag |

// 생성자에대해서..

// 1. 생성자의모양, 언제호출되는가?

// 2. 생성자를1개도만들지않으면컴파일러가기본생성자1개를제공한다.

 

#include <iostream>

using namespace std;

 

class Point

{

private:

        int x;

        int y;

public:

        Point()                       // 1

        {

               Point(0, 0);   // 생성자에서다른생성자호출!!

               x = 0;

               y = 0;

               cout << "Point()" << endl;

        }                                    

        Point( int a, int b ) { x = a; y = b; }     // 2

};

 

class Rect

{

        Point p1;

        Point p2;

public:

        Rect()

        {

               cout << "Rect()" << endl;

        }

};

 

void main()

{

        Rect r; // ?

 

 

        Point* p5;             // 객체가아니라포인터이다. 생성자호출안됨

 

        Point* p6 = (Point*)malloc( sizeof(Point) ); //생성자호출안됨.

        Point* p7 = new Point; // 생성자호출

 

        Point p;

        //p.Point();           // 생성자의명시적호출은안된다.!!!

 

        Point p3[10];  // 1번생성자를10번호출

        Point p4[5] =
         { Point(1, 2), Point(2, 3) };  // 2
번생성자2, 1번생성자3번호출

 

        Point p1;

        Point p2( 1, 2 );

}

 

Tag |

#include <iostream>

using namespace std;

 

// stack이필요하다.

// 1. type을만들지않은경우

//    단점: Stack 2개이상필요한경우복잡해진다.

 

 

int buf[10];

int top = 0;

 

void push( int a )

{

        buf[top++] = a;

}

 

int pop()

{

        return buf[--top];

}

 

void main()

{

        push( 10 );

        push( 20 );

 

        cout << pop() << endl;

        cout << pop() << endl;

}

 

 

// 2. Stack이라는Type을먼저만들자- 구조체사용

 

struct Stack

{

        int buf[10];

        int top;

};

 

void init( Stack* s )         { s->top = 0; }

void push( Stack* s, int n)   { s->buf[s->top++] = n; }

int  pop( Stack* s )           { return s->buf[--s->top]; }

 

int main()

{

        Stack s1;

        Stack s2;

        init( &s1 );

        push( &s1, 10 );

 

        cout << pop( &s1 ) << endl;

 

        return 0;

}

 

 

// 3. 함수와Data를묶어서표현하자.

// Type 설계의원칙: 잘못사용하기어렵게만들어라.

 

struct Stack

{

private:                      // 멤버함수만접근할수있다.

        int buf[10];

        int top;

 

public:                       // 모든곳에서접근할수있다.

        // 멤버함수: 멤버Data에바로접근할수있다.

        //void init() { top = 0; }            //생성자역할.

        Stack() { top = 0; }

 

        void push( int n ) { buf[top++] = n; }

        int  pop() { return buf[--top]; }

};

 

void main()

{

        Stack s1;

        Stack s2;

 

        //s1.init();

        s1.push(10);

 

        //s1.top = 100;               // private: 영역!!

 

        cout << s1.pop() << endl;

}

 

// 4. 동적메모리할당사용

 

struct Stack

{

private:                     

        int* buf;

        int top;

 

public:                      

        // 생성자: 객체를생성하면자동으로호출되는함수

        Stack( int sz = 10 )

        {

               top = 0;

               buf = new int[sz];

        }

 

        // 객체가파괴될때자동으로호출된다.

        ~Stack() { delete[] buf; }

 

        void push( int n ) { buf[top++] = n; }

        int  pop() { return buf[--top]; }

};

 

void main()

{

        Stack s1;

        Stack s2(30);

 

        s1.push(10);

 

        cout << s1.pop() << endl;

}

 

 

// 5. Template 기반의Stack

 

template <typename T>

struct Stack

{

private:                     

        T* buf;

        int top;

 

public:                      

        // 생성자: 객체를생성하면자동으로호출되는함수

        Stack( int sz = 10 )

        {

               top = 0;

               buf = new T[sz];

        }

 

        // 객체가파괴될때자동으로호출된다.

        ~Stack() { delete[] buf; }

 

        void push( T n ) { buf[top++] = n; }

        T    pop() { return buf[--top]; }

};

 

void main()

{

        Stack<int> s1;       // template class( struct )의객체를생성하는방법

        Stack<double> s2(30);

 

        s1.push(10);

 

        cout << s1.pop() << endl;

}

 

template <typename T>

struct List

{

        T buf;

        List* link;

 

        List()

        {

               link = NULL;

        }

};

 

template <typename T>

struct Stack

{

private:                     

        List<T>* pList;

        int tail;

 

public:                      

        // 생성자: 객체를생성하면자동으로호출되는함수

        Stack()

        {

               tail = 0;

        }

 

        // 객체가파괴될때자동으로호출된다.

        ~Stack()

        {

        }

 

        void push( T n )

        {

               pList = new pList;

               pList->buf = n;

        }

 

        T pop()

        {

               return buf[--top];

        }

};

 

void main()

{

        Stack<int> s1;   // template class( struct )의객체를생성하는방법

 

        s1.push(10);

 

        cout << s1.pop() << endl;

}

 
6. Single linked list 기반의 template Stack

#include <iostream>

using namespace std;

 

template <typename T>

class List

{

public:

        T m_Data;

        List* m_pNext;

 

        List(T n, List* next) : m_Data(n), m_pNext(next)

        {}

        ~List()

        {

               if( m_pNext != NULL )

                       delete m_pNext;

        }

};

 

template <typename T>

class Stack

{

        List<T>* m_pList;

 

public:

        Stack();

        ~Stack();

 

        bool IsEnd();

 

        void push( T n );

        T pop();

};

 

template<typename T>

Stack<T>::Stack() : m_pList(NULL)

{}

 

template<typename T>

Stack<T>::~Stack()

{}

 

template<typename T>

bool Stack<T>::IsEnd()

{

        return (m_pList == NULL);

}

 

 

template<typename T>

void Stack<T>::push( T n )

{

        m_pList = new List<T>( n , m_pList );

}

 

template<typename T>

T Stack<T>::pop()

{

        if( IsEnd() )

        {

               cout << "Stack is End" << endl;

               return -1;

        }

       

        List<T>* temp = m_pList;

        T data  = m_pList->m_Data;

        m_pList = m_pList->m_pNext;

 

        temp->m_pNext = NULL;

        delete temp;

 

        return data;

}

 

void main()

{

        Stack<int> s1;

        s1.push( 10 );

        s1.push( 20 );

        s1.push( 30 );

 

        cout << s1.pop() << endl;

        cout << s1.pop() << endl;

        cout << s1.pop() << endl;

 

        Stack<double> s2;

        s2.push( 4.20 );

        s2.push( 5.560 );

 

        cout << s2.pop() << endl;

        cout << s2.pop() << endl;

 

//      Stack<char*> s3;

//      s3.push("문자열??");

//      s3.push("출력가능??");

//      cout << s3.pop() << endl;

//      cout << s3.pop() << endl;

//      cout << s3.pop() << endl;

}

 

Tag |

7.25(수) C++ 기초문법 - OOP 개념

from Study/C++ 2007/07/26 23:59 view 17393

// OOP 개념= 필요한Type을먼저설계하자. ( 프로그램이훨씬간단해진다. )

// C: 객체기반(Data만으로Type을설계한다.)

// C++: 객체지향( Data+Function 으로Type을설계하자. )

 

#include <iostream>

using namespace std;

 

struct Complex

{

        int real;

        int image;

 

        Complex Add( Complex c1, Complex c2 )

        {

        Complex temp;

 

        temp.real  = c1.real  + c2.real;

        temp.image = c1.image + c2.image;

 

        return temp;

        }

};

 

void main()

{

        Complex c1 = { 1, 1 };

        Complex c2 = { 2, 2 };

 

        Complex c3 = c3.Add( c1, c2 );

}

 

/*

//복소수2개의합을구하고싶다.

 

 void Add( int ar, int ai, int br, int bi,    // in Parameter

         int* sr, int* si )                   // out Parameter

{

        *sr = ar + br;

        *si = ai + bi;

}

 

void main()

{

        int ar = 1, ai = 1;           // 1+ 1 i

        int br = 2, bi = 2;           // 2+ 2 i

        int sr, si;

 

        Add( ar, ai, br, bi, &sr, &si );

}

*/

Tag |

6교시

//
동적메모리할당
 

// 1. 왜동적메모리할당을사용하는가?

//    주로실행시간결정된값으로메모리를할당하기위해.


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

// 배열의크기에대해서


void
foo( const int c )

{

        int ar[c];        // error. 실행해봐야알수있다.(컴파일시간에결정!!)

}

 

int main()

{

        const int x = 10;

        int ar[x];       // ok.

 

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

        int br[ sz[1] ]; 
       
// error.
배열의크기는상수가아니라

        // 컴파일시간에크기를알아야하는것이다.

        // sz[1] => *(sz+1)

}

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

void main()

{

        //C++

        int* p1 = new int;

        int* p2 = new int[10];

 

        delete p1;

        delete[] p2;

 

        int* p3 = new int(3);  // 3으로초기화

 

        // 2차원배열의주소는1차원배열포인터로가르키면된다.

        int(*p4)[10] = new int[10][10];              // 2차원배열형태로.

       

        int* p6 = new int;

        free(p6);              // undefined

 

        int* p7 = new int[10];

        delete p7;             // undefined

 

        int n;

        cout << "학생수를넣어주세요. >>";

        cin >> n;

 

        // 학생수만큼의메모리를할당하고싶다.   

        //int jumsu[n]; 
       
//
배열의크기는변수가될수없다. 상수이어야한다.

 

        int* jumsu = (int*)malloc( sizeof(int)*n );         

}

Tag |