Tech & IT/프로그래밍

C++ Template 활용(Android쪽 코드)

해피콧 2012. 3. 19. 22:01
'); }
'); }
// intro1day.cpp : Defines the entry point for the console application.
//

//#include "stdafx.h"


#include <iostream>
using namespace std;

#if 0

//int_cast만드는 연습(interface cast와 비슷, 최상위 class에는 pure virtual 함수로 작성해서 
//하위 class에서 강제로 toInt를 만들게 한다면 interface_cast가 될 것
class Test
{
public:
//Test 클래스는 int값을 하나 꺼낼 수 있다고 가정해 봅시다.
static int toInt() {return 10;}
};

template<typename T> int int_cast(T obj)
{
return T::toInt();
}

int main()
{
//int n = Test::toInt();
Test t;
int n = int_cast<Test>(t);
printf("%d",n);
}
#endif

#if 0
//1. 함수템플릿
//    - T가 결정되어서 함수가 되는 과정을 인스턴스화 라고 한다.
//      암시적/명시적 인스턴스화가 있다.
template<typename T> T Max(T a, T b)
{
return a < b ? b: a;
}

int main()
{
cout << Max(1,3) << endl; // int Max(int, int) 버전의 함수를 생성
cout << Max(3.4, 2.1) << endl; // doudle Max(double, double) 버전의 함수를 생성

cout << Max<int> (65, 'B') << endl; //함수템플릿의 T를 명시적으로 지정하는 방법.

return 0;
}
#endif

#if 0
//클래스 템플릿..!!
template<typename T> class complex
{
T real;
T image;
publid:
complex(T a = 0, T b = 0): real(a), image(b) {}

//복사생성자
//U가 T로 변환된다면 complex<U>도complex<T>로 변환되어야 한다. - template복사생성자 필요
template<typename U> complex( const complex<U>&c )
{
real = c.real;
image = c.image;
}

template<typename U> friend class complex;
};



itn main()
{
complex<int> c1(1,2);
complex<int> c2 = c1;

complex<double> c3 = c1; //뭘까요? ..
}
#endif

#if 0 // 이거 앞으로 잘 활용할 수 있을 것 같은데 dkim
//Mix in template - 안드로이드에서 자주 사용하는 기법.
template<typename T>
class A
{
public:
void foo() { static_cast<T*>(this)->goo();} //T는 내 자식일것임 자기 자신(this)를 자기 자식으로 casting함 결국 자식께 부르게 됨
void goo() {cout << "A::goo" << endl;} //1 가상함수는 자식이 재정의하면 자식꺼를 부르게 해주자
//가상함수를 너무 많이 쓰면 성능 저하의 원인이다 그래서 가상함수 빼고 해 보겠음
// template를 이용해서 가상함수를 사용해야 할 것을 해결함 속도 증가

};

//부모가 template이고 그 템플릿이자로 현재 클래스의 이름을 보내는 기술..
// Mix in Template이라고 부른다. 여러가지 활용이 가능한데.. 아래의 경우는 비가상함수를
// 가상함수 처럼 동작하게 하는 기술이다.
class B :public A<B>
{
public:
void goo() { cout << "B::goo" << endl;} //2
};

int main()
{
B b;
b.foo(); // 1? 2?
}
#endif

#if 0 // wow~ dkim
// Mix in template 2 - 안드로이드에서 자주 사용하는 기법.
template<typename T> 
class A
{
protected:
~A() {cout << "~A()" << endl;}
void foo() {cout << "A::foo" << endl;}

public:
void clean()
{
delete static_cast<T*>(this);
}
};

class B: public A<B>
{
public:
~B() {cout << "~B()" << endl;}
virtual void foo() {cout << "B::foo" << endl;}

};

int main()
{
A<B>* p = new B; 
//virtual이 없는 foo라면부모 객체로 자식instance를 가리킬 때는 C++에서는 foo부르면 부모께 불림(메모리 안보고 타입만봄(정적언어 complile time)
//실행할 때 메모리를 보고 결정하라고 하는게 virtual이라는 keyword임
//그래서 foo에 virtual을 붙이면 자식꺼 부름

//p->foo();
//delete p; //이건? 소멸자가 항상 virtual이어야 하는 이유임
//그런데 virtual은 느리니까 virtual 빼고 protected로 만들면?
//부모 소멸자가 protected니까 error가 나는데 
// 이제 B의 소멸자를 호출하기 위해 꼭 캐스팅해서 사용하자. 불편하지만 제대로 호출된다.!
//delete static_cast<B*>(p); //이렇게 하니까 잘 되긴 하지만 불편하다.
//그래서 clean을 만들어보자
p->clean(); //가상함수 테이블이 없어진 가벼운 객체가 만들어졌으므로 이제 쉽게 쓰자
}
#endif

#if 0 
//상속과 upcasting(부모포인터로 자식 객체를 담을 수 있다)
// * 이런 장점을 활용하여 동종을 저장하는 컬렉션을 만들 수 있다.
//      그리고 동종(동일부모자식)을 처리하는 함수를 만들 수 잇다.
// * 모든 자식의 공통의 특징은 부모에 있어야 한다.
// * 
#include <vector> //STL vector .. 안드로이드에서도 있습니다.
//도형 편집기를 만들어 보자. - 아주 많은 개념이 등장합니다 꼭 알아두세요..
// 1. 각 도형의 특징을 관리하는 타입을 만들어보자
// 2. 동일 부모가 있다면 모든 도형을 묶을 수 있지 않을까???
// 3. 모든 자식은 공통의 기능은 반드시 부모로 부터 제공되어야 한다.
// 4. 자식이 재정의 하게 되는 함수는 반드시 가상함수로 하자.
// 5. OCP 이론 
//    다형성이 좋은 점은 나중에 기능(class)가 추가되어도 이 code는 수정할 필요가 없음
//    객체지향의 원칙 중 OCP : Open Close Principle : 기능 추가에 열려 있고(open), 코드 수정에 닫혀(Close)있어야 한다는 이론(Principle)
// 6. 
class Shape
{
public:
// template method : 변하지 않는 전체적인 알고리즘은 부모가 public 비 가상함수로 만들고
//                   변해야 하는 세부 알고리즘은 자식이 prottected가상함수로 재정의 하도록 하는 디자인
void Draw() //자식에게 재정의하지 못하게 하면 좋겠지만 C++은 그런 기능은 없고, 최소한 virtual은 빼자
{
//Mutex.Lock();
OnDraw();
//Mutex.Unlock();
}
public:
virtual void OnDraw() = 0; //pure virtual func.. 자식이 반드시 만들어야함(강제)
                          //이런 디자인 기법을 template Method라고 부른다.

};


class Rect : public Shape
{
protected :
virtual void OnDraw() {cout << "Rect::Draw" << endl;}
};
class Circle : public Shape
{
protected: //RealDraw를 직접 부르면 Mutex를 못쓰니까 못쓰게 막자(private는 자기네들끼리도 못하게 하니까 protected로)
virtual void RealDraw() {cout << "Circle::Draw" << endl;}
};


int main()
{
vector<Shape*> v;
while(1)
{
int cmd;
cin >> cmd;
if(cmd==1) v.push_back(new Rect);
else if (cmd == 2) v.push_back(new Circle);
else if(cmd == 9)
{
for(int i = 0; i < v.size(); i++)
v[i]->Draw(); //다형성 , 동일 함수 호출 표현식이 상황에 따라 다른 함수를 호출함

}
}
}

#endif

#if 0
#include "List.h" /// froyo/framework/base/include/utils에 sp, RefBase, list, vector등이 있습니다.
using namespace android; //안드로이드의 모든 클래스는 이 안에 있습니다.

// 요즘 C++의 콜렉션 클래스(뭔가를 저장하는 클래스)를 이해하려면 반복자를 알아야 합니다.

int main()
{
List<int> st;

st.push_back(10);
st.push_back(20);
st.push_back(30);
st.push_front(40);

st.insert(++st.begin(), 100);
List<int>::iterator p = st.begin(); // p는 st의 처음을 가리키는 포인터 역할을 함
List<int>::iterator p1 = st.end(); //st의 마지막을 가리키는 포인터

while(p != st.end())
{
cout << *p << endl;
++p;
}


//마지막 요소 제거하기
st.erase(--p1); //st의 마지막을 가리키는 포인터
p = st.begin();
//while(p != st.end())
//{
// cout << *p << endl;
// ++p;
//}
}
#endif

//1. 부분전문화 개념

/*
//primary template
template<typename T> class Stack
{

};

//부분 전문화
template<typename T> class Stack<T*>
{

};

//전문화 버전
template<typename T> class Stack<char*>
{

};

int main()
{
Stack<int> s1;
Stack<int*> s2;
Stack<char*> s3;
}
*/


//안드로이드가 사용하는 가장 복잡한 template기술 - traits 기술
// traits란? T가 pointer인지 아닌지, 구조체인지 아닌지 공용체인지 아닌지를 알아내는 기술
/*
template<typename T> T Max(T a, T b)
{
if(T is Pointer)
return *a < *b ? b : a;
return a < b ? b : a ;
};

int main()
{
int x = 10, y = 20;

Max(x,y);
Max(&x, &y);
}
*/

//T가 포인터인지 알아내는 기술(한마디로 컴파일러에게 물어본거)
// framework/base/include/utils/typehelpers.h

// primary template 은 FALSE리턴
template<typename T> struct trait_pointer
{
enum{value = false};
};
//부분전문화 버전은 TRUE 리턴
template<typename T> struct trait_pointer<T*>
{
enum{value = true};
};
// primary template 은 FALSE리턴
template<typename T> struct trait_array
{
enum{size = 0};
enum{value = false};
};
//부분전문화 버전은 TRUE 리턴
template<typename T, int N> struct trait_array<T[N]>
{
enum{size = N};
enum{value = true};
};
template<typename T> void foo(const T& a)
{
if(trait_array<T>::value) 
cout << "Array, " << "Size is " << trait_array<T>::size << endl;
else
cout << "not Array" << endl;

if(trait_pointer<T>::value)
cout << "Pointer" << endl;
else
cout << "not Pointer" << endl;
};

int main()
int n[] = {0,1,2};
foo(n);
}



=============================
Default 생성자 관련


class Animal
{
public:
Animal() {cout << "Animal Ctor" << endl;}
Animal(char * sz) {cout << "Animal Ctor(char)" << endl;}

};

class Dog : public Animal
{
public:
Dog() : Animal() {cout << "Dog Ctor" << endl;}
Dog(char * sz) : Animal(sz) {cout << "Dog Ctor(char)" << endl;} //Default 생성자를 이해해야 함
};

int main()
{
Animal a;
Animal a2("aa");
cout << "---------------" << endl;
Dog d1;
Dog d2("aaa");
}

 =========================================
#if 0
template<typename T> class Stack
{
public:
//다음 중 생성자로 맞는 것은?
Stack() { cout << "Stack" << endl;}   // ok...
//Stack<T>() {}                       // error

//복사생성자
Stack(const Stack& s) {} // 함수인자로는 2번이 정확한 표현이지만 이 표현도 허용
Stack(const Stack<T>& s) {} //ok

//클래스 템플릿의 멤버 함수를 외부 구현
void push(const T* a);

// 클래스 템플릿의 멤버 함수 템플릿.. 
// 예)complex만들기 complex<double> = complex<int>가 되게 하기 위해 복사생성자를 아래처럼 구현했었음
template<typename U> T foo(U a);
};

//복사생성자와 대입연산자 만들때만 이런식으로 하게 된다.  android에서는 sp에서 복사, 대입에 나옴
template<typename T> template<typename U> T Stack<T>::foo(U a)
{

}

//둘 중 어느게 맞는건가요?
template<typename T> void Stack::push(const T& a)        // error
template<typename T> void Stack<T>::push(const T& a)     // ok
{

}
#endif


=====================================================
#if 0
//템플릿 인자의 3가지 종류 
template<typename T> class List
{

};

template<typename T, int N> class Stack1
{
T buff[N];
};

template<template<typename> class C, typename T> class Stack2
{
C c; // error
c<T> c; // ok

};

int main()
{
List ss; // List는 템플릿이다
List<int> s; //List는 타입이다.
Stack1<int, 10> s2;    
Stack2<List, int> s3;


==> template인자로 들어갈 수 있는 것은 3가지 ==> 타입, 정수, 템플릿
}
#endif

================================================================ 
  
//template을 사용해서 부모가 바귀게 하는 기술.. BpInterface/BnInterface가 사용하는 기술
template<typename T, typename ThreadModel> class List : public ThreadModelList
{
public:
void push(const T&a )
{
Lock();
...
Unlock();
}
};

class MultiThread
{
public:
void Lock() {mutex.lock();}
void UnLock() {mutex.Unlock();}
};

class SingleThread
{
public:
void Lock(){}
void UnLock() {}
};
// 사용한는 방법 ------------------------
// 부모를 가져다 쓰는 순간에 결정함
List<int, MultiThread> st;
List<int, SingleThread> st; //어짜피 최적화되면 성능저하 없음

 ================================================================