8.1(수) C++ - template 전문화

from Study/C++ 2007/08/02 18:05 view 22541

// template 전문화가 요즘들어 인기를 얻고 있는 이유. - 메타의 세계

// 컴파일시간에 어떤일을 수행하게 하는 기법. 컴파일시간은 오래 걸리지만

// 실행시간이 단축된다. 주로 전문화를 사용해서 컴파일 재귀호출을 사용한다.

// 하지만 컴파일 역량이 있기 때문에 9번이상?? 은 안된다. 왜그렇까..컴파일 하기 싫은가..


template
<int n> class Pow

{

public:

        enum { result = n * Pow<n-1>::result };

};

 

template<> class Pow<0>

{

public:

        enum { result = 1 };

};

 

void main()

{

        int n = Pow<5>::result;


       
cout << n << endl;

}

 

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

// Template 전문화( 특화, Specialization ).

template<typename T, typename T2> class Test {};     // 1

template<typename T> class Test<T, int> {};          // 2

 

Test<int, double> t1;  // 1

Test<int, int> t2;     // 2

 

// Primary Template

template<typename T> class Stack

{

        T* buf;

};

 

// 전문화 Template

template<> class Stack<int>

{

};

 

// 부분전문화- 모든 포인터는 이 클래스 사용

template<typename T> class Stack<T*>

{

        T* buf;

};

 

void main()

{

        Stack<int> s;

}

 

Tag |

8.1(수) C++ - typename

from Study/C++ 2007/08/02 17:17 view 22190

#include <iostream>

using namespace std;

 

// typename 문법이야기

// 1.2 의 중복문제가 발생해서 이를 해결하고자 typename 키워드를 만들었다.

// 그러고 보니 class T 라는 것의 의미가 명확하지가 않는 것을 알 수가 있었다.

// class Tint와 같은 타입도 받을 수 있기 때문에 typname으로 바뀌게 된 것이다.!!!

// 하지만 class는 여전히 지원된다.

 

template<typename T> void foo( T a )

{

        typename T::B* p;
        // 1. T
안에 내포클래스로 B가 있는데 그 포인터 p를 선언.

        // 2. T안에 B라는 static 변수가 있는데 곱하기 p를 한다.

}

 

class A

{

public:

        static int B;

 

        class B

        {

        };

};

 

void main()

{

        A a;

        foo( a );

}


//////////////////////////////////////////////////////////////////// 
// 디폴트 인자

template<typename T = int, int n = 10> class Stack

{

        T buf[n];

};

 

void main()

{

        Stack<int, 10> s;

        Stack<int> s2;

 

        stack<> s3;    // 모두 default 사용

}

Tag |

8.1(수) C++ - template 파라미터

from Study/C++ 2007/08/02 16:43 view 21280

#include <iostream>

#include <vector>

using namespace std;

 

// template 파라미터의종류

// 1. type

// 2. 상수( 정수와포인터상수만가능) 파라미터.

// 3. template temlpate 파라미터- template 이름을 넘긴다???

 

// vector는 디폴트 인자가3 개가 있으므로 넘기기 힘들다.

// 그래서 새롭게 만든 template를 넘겨보자!! VECTOR

template<typename T> class VECTOR

{

};


template
<template<typename> class A, typename T> class Stack

{

        A<T> v;

public:

};

 

int main()

{

        Stack<VECTOR, int> s;

 

        return 0;

}


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

template <typename T, int n, template<typename> class A> class Stack

{

        A<T> v;                // 결국 vector<int> v

        T buf[n];              // 배열첨자에 템플릿인자 상수는 가능하다.

};

 

void main()

{

        vector<int> a;

        vector b;

 

        Stack<int, 10, vector> s;

 

        int n = 10;

        //Stack<int, n> s2;    // error

}


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

// 클래스template 2 

typedef vector<vector<int> > Matrix;

 

void main()

{

        //vector<vector<int> > m(3, 3);

        Matrix m(3, 3);

       

        m[0][0] = 10;

       

        vector<int> v(10, 3);

 

        v[0] = 10;

}

 

//////////////////////////////////////////////////////////////////// 
template
<typename T> class Stack

{

};

void main()

{

        Stack<int> s;

        Stack<Stack<int> > s2; // >> 와 혼동 되지 않도록 해야 한다.

}

 

Tag |

// 클래스 template의 기본.
template
<typename T> class Stack

{

        T* buf;

public:

        Stack() {}             // 1. ok. 생성자이름은클래스이름

        //Stack<T>() {}        // 2. 에러

 

        // 복사생성자의모양

        Stack( const Stack<T>& ) {}

 

        void push ( T a );

};

 

// 클래스template의멤버함수를외부에구현하려면

template<typename T> void Stack<T>::push( T a )

{

}

 

void main()

{

        Stack<int> s1;

//      Stack      s2;  // error. Stack template의이름이지Type이아니다.

                        // typeStack<T> 이다.

}



// 멤버 함수 template를 활용해보자.!!! 

template<typename T> class Stack

{

public:

        Stack(){}

        template<typename U> explicit Stack(const Stack<U>&)

        {

        }

        explicit Stack(const Stack<T>&)

        {

        }

 

};

void main()

{

        Stack<int> s1;

        Stack<int> s2(s1);

 

        Stack<int> s3;

        Stack<double> s4(s3);

}

 

 

Tag |

8.1(수) C++ - 함수 template

from Study/C++ 2007/08/02 16:00 view 24405

#include <iostream>

using namespace std;

 

// 1. 함수template

// (1) instantiation : T -> 특정 type으로 변경되는 과정.

// (2) template 의원리: Code Generation ->
//      단점: Code Bloat(코드가커질수있다.),2번 컴파일 한다.

// (3) template 2번문법을 확인하게 된다.

// (4) internal linkage를가진다.(완전한 구현체를 가져야 한다.),다른파일에 정의하면 에러

//             클래스template를 만들때에서 선언과 구현 모두 헤더에 넣어야 한다.

// (5) 함수template overloading 된다.

 

template <typename T> T Max( T a, T b )  // 1

{

        return a < b ? b : a;

}

 

int Max( int a, int b )                  // 2

{

        return a < b ? b : a;

}

 

void main()

{

        cout << Max( 1, 2 ) << endl;     // 2

        cout << Max( 3.4, 3.2 ) << endl; // 1

        // 2. 6.0은에러.int버전이없다면Tambigous 하다는에러.
       
cout << Max( 65, 'B' ) << endl;

}

Tag |

7.31(화) C++ - Composite 패턴

from Study/C++ 2007/08/02 15:53 view 25452

#include <iostream>

#include <string>

#include <vector>

using namespace std;

 

// 폴더와File의공통의부모

class Item

{

        string name;

public:

        Item( string s ) : name ( s ) {}

     
        // 상수함수로만들어야상수함수에서불러올수있다.  

        string GetName() const { return name; }       

 

        virtual int GetSize() = 0;

 

       // Getname을상수함수로만들자!!
       
virtual void print( string prefix ) const
        {

               cout << prefix << GetName() << endl;

        }

};

 

class File : public Item

{

        int size;

public:

        // 부모클래스에디폴트생성자가없으므로명시적으로부모생성자를호출해줘야한다.

        File( string n, int s ) : Item(n), size(s) {}

 

        virtual int GetSize() { return size; }

};

 

class Folder : public Item

{

        vector<Item*> items;

public:

        Folder( string n ) : Item(n) {}

 

        void Add( Item* p ) { items.push_back(p); }

 

        virtual int GetSize()

        {

               int sz = 0;

               for ( int i = 0; i < items.size(); ++i )

               {

            // 다형성( Polymorphism ), 가상함수를통해객체에따라다른기능을제공한다.

                       sz += items[i]->GetSize();

               }

               return sz;

        }

 

        virtual void print( string prefix ) const

        {

               cout << prefix << GetName() << endl;  // 먼저자신의이름출력

               prefix = prefix + string("\t");

 

               for ( int i = 0; i < items.size(); ++i )

               {

                       items[i]->print( prefix );

               }

        }

};

 

void main()

{

        Folder* R = new Folder("ROOT");

        Folder* A = new Folder("A");

        Folder* B = new Folder("B");

 

        R->Add(A);

        R->Add(B);

 

        R->Add( new File( "a.txt", 10 ) );

        A->Add( new File( "b.txt", 20 ) );

        B->Add( new File( "c.txt", 30 ) );

 

        cout << R->GetSize() << endl;

 

        R->print("");

}

 

Tag | ,

7.31(화) C++ - 추상클래스

from Study/C++ 2007/08/02 15:46 view 20920

// 순수 가상함수 와 추상클래스

// 의미: 자식에게 반드시 특정함수를 만들게 하는것!

// Abstract Base Class 추상기반클래스

 

// 강한결합 tightly compling 값에 의한 전달!

// 약한결합 loosely compling 인터페이스에 의한 결합


//
사람과 전화기 제조업자가 지켜야 하는 계약서를 먼저 만든다. ( interface, contract )
// 인터페이스 설계의 중요성 : 확장성, 변화에 유연해 진다.
//
구현 부분이 없기 때문에 메모리를 잡지 않는다.

#define interface struct      //왠지 의미전달이 제대로 된다.멋있음.!!!

interface IPhone

{

        virtual void Calling( char* num ) = 0;

};

class IMP3Play

{

public:

        virtual void MP3Play() = 0;

};

 

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

// 계약에 따른 전화기를 사용하는 객체

class People

{

public:

        void UsePhone( IPhone* p )    { p->Calling("119"); }

};

 

// 모든 전화기는 IPhone 인터페이스를 구현해야(상속 받아서 순수가상함수 재정의) 한다.

class AnyCall : public IPhone

{

public:

        void Calling( char* ) {}

};

 

void main()

{

        People p;

        AnyCall a;

 

        p.UsePhone( &a );

}

 

Tag |

7.31(화) C++ - typeid, type_info

from Study/C++ 2007/08/02 15:29 view 22011

#include <iostream>

#include <typeinfo.h>
using
namespace std;
 

// template에서instatiation type을알아보는방법

// const T& char const[6] 그러므로문자열의길이가다르다면에러!!

// T char const* 으로타입이결정된다.

// 그러므로타입을정할때조심해서정해야한다.!!!

template<typename T> void foo( T a, T b )

{

        cout << typeid(a).name() << endl;

}


template<typename T> void goo( const T& a, const T& b )

{

        cout << typeid(a).name() << endl;

}


void main()

{

        foo( "hello", "hel" );

        goo( "hello", "hello" );

        //goo( "hello", "hel" ); // error
}

 

///////////////////////////////////////////////////////////////////
// RTTI : Run Time Type Information

class A

{

public:

        virtual ~A() {}               // 상속이라면100% 가상함수를쓰게된다.

};

 

void foo( B* p )

{

}

 

class B : public A

{

public:

};

 

void foo( A* p )

{

        // 여기서pA인지B인지를알고싶다면!!

        // B* pp = (B*)p; // error A가넘어오게되면undefine??

 

        // 방법1. typeid() 연산자사용

        const type_info& t = typeid(*p); // 6.0에서는\GR 옵션을줘야한다.

        cout << t.name() << endl; // 가상함수가있어야제대로동작한다(소멸자라도추가)

 

        if ( typeid(*p) == typeid(B) )

        {

               B* pp = (B*)p; // 안전하다.

        }

 

        // 방법2. 이거만하도록나온dynamic_cast. DYNAMIC_CAST() <-- MFC

        B* p2 = dynamic_cast<B*>(p);  // down cast 가발생하면0이리턴된다.

        if ( p2 != 0 )

        {

               // p2사용

        }

}

 

void main()

{

        B b;

 

        foo( &b );

}

 

Tag |

// 파워포인트 같은 프로그램을 만들고싶다.

// 1. prototype 디자인패턴. - 가상복사생성자

// 2. Template Method 디자인패턴( C++에서는NVI라고도불린다. )

 

// VC2005 에서는반환형을자기로가져도된다. 아래참고

//      virtual Shape* Clone() { return new Circle(*this); }

//      virtual Circle* Clone() { return new Circle(*this); }

 

class Shape

{

public:

        // 자신의 복사본을 만들어내는 가상함수-> 가상복사생성자(prototype 디자인패턴)

        virtual Shape* Clone() { return new Shape(*this); }

 

        // 비가상함수.. public 에가상함수를놓지말자.

        void Draw()

        {

               // 멀티스레드를대비해서동기화객체를얻는다.

               RealDraw();    // 내부구현에서 가상함수를 호출하자.

               //cout << "Shape::Draw" << endl;

               // 동기화 객체를 반납한다.

        }

protected:

        // 모든 가상함수는 protected에 놓자.

        virtual void RealDraw()

        {

               cout << "Shape::Draw" << endl;

        }

};

 

class Rectangle : public Shape

{

public:

        void RealDraw()        { cout << "Rectangle::Draw" << endl; }

 

        virtual Rectangle* Clone() { return new Rectangle(*this); }

};

 

class Circle : public Shape

{

public:

        void RealDraw()        { cout << "Circle::Draw" << endl; }

 

        virtual Circle* Clone() { return new Circle(*this); }

};

 

void main()

{

        Shape* buf[1000];      // 동종의 객체(모든종류의도형)을 보관 할 수 있다.

        int count = 0;

 

        int cmd;

        while ( 1 )

        {

               cin >> cmd;

               if ( cmd == 4 )

               {

                       cout << "몇번째 도형을 복사할까요? >> ";

                       int k;

                       cin >> k;

 

                       buf[count++] = buf[k]->Clone();

               }

               if ( cmd == 1 ) buf[count++] = new Rectangle;

               if ( cmd == 2 ) buf[count++] = new Circle;

               if ( cmd == 3 )

               {

                       for ( int i = 0; i < count; ++i )

                              buf[i]->Draw();       // 다형성을띠게된다.

               }

        }

}

 

Tag | ,

7.31(화) C++ - 가상함수 테이블

from Study/C++ 2007/08/02 14:46 view 28327

가상함수 테이블(vtbl) 과 가상함수 테이블 포인터(vptr)

- 대부분의 컴파일러는 가상함수의 기능을 구현하기 위해 가상함수 테이블과 가상함수 테이블

포인터를 사용한다. 가상함수를 선언했거나 상속받은 클래스에는 가상함수의 모든 주소를 가

지고 있는 배열(혹은 링크드 리스트)이 생기는데 이를 가상함수 테이블 이라고 한다.

또한, 해당 클래스의 객체를 생성하면 해당 객체에는 멤버 data외에 가상 함수 테이블을

가르키는 포인터가 추가된다. 이를 가상함수 테이블 포인터라고 한다.

결국 가상함수를 사용하게 되면 실행시간 다형성(Run-time Polymorphism)을 얻을 수 있는 반면,

1. 가상함수 테이블을 위한 메모리 할당
( 가상함수가 많거나 상속이 깊을 경우 메모리 사용량이 많아진다. )

2. 객체 생성시 vptr의 추가로 인한 객체의 크기 증가
( 작은 객체 일 경우 상당히 비효율적 )

3. 함수 호출시 함수 포인터에 의한 호출로 약간의 오버헤드 발생

4. Inline을 사용할 수 없으므로 속도가 훨씬 느려진다.

// 예제 1.

class A

{

public:

        virtual void foo() { cout << "A::foo" << endl; } // 1

};

 

class B

{

public:

        virtual void goo() { cout << "B:goo" << endl; } // 2

};

 

void main()

{

        A a;

        B* p = (B*)&a;

 

        p->goo();      // 1을 출력한다.

}


// 예제 2.
// 가상함수의 테이블을 이해했다면 이건 메모리 참조에러가 나온다.

class A

{

        int x;

public:

        void foo() { cout << "A::foo" << endl; }

};

 

class B

{

        int y;

public:

        virtual void goo() { cout << "B:goo" << endl; } 

};

 

void main()

{

        A a;

        B* p = (B*)&a;

 

        p->goo();      // error

}


// 예제 3. 

// p->foo() 에서 디폴트 값은 컴파일 시간에 결정된다.!!!
class
A

{

public:

        virtual void foo( int a = 10 )
        { cout << "A::foo("<< a << ")" << endl; }    // 1

};

 

class B : public A

{

public:

        virtual void foo( int a = 20 )
        { cout << "B:foo("<< a << ")" << endl; }    // 2

};

 

void main()

{

        A* p = new B;

       

        p->foo();    // 디폴트 매개변수는 부모에게서 받아오고 출력은 2로 한다. 

 

        delete p;

}


Dynamic Binding -> 실행 시 결정된다.

= late binding

// Dynamic_Binding (가상함수 호출시는 처음) 메모리에서 처음 가상함수를 읽어온다.

Static Binding -> 컴파일러가 컴파일시 결정.

= early binding

// Static_Binding 자기를 호출하는 놈을 부른다. 메모리가 아니라 타입을 읽어온다.


컴파일 타임에는 타입을 보므로 디폴트타입을 정할떄에는 컴파일시 실행되므로 디폴트 값은 타입으로 가지고 호출하는 것은 메모리 즉, 포인터로 정해진 함수를 읽어온다.!!!

 

 

Tag |