반응형
http://ngcbbs.tistory.com/15

단하게 C/C++ 을 알고 있는 사용자에게 설명하면 함수 포인터 같은녀석! 이라고 이야기 할 수 있겠다.

다만 사용 방법이나 다중 위임의 형태를 C/C++ 에서 구현하기 위해서는 잡다한 코드가 더 추가되어야 하지만 정말 간편하게 다중 위임으로 처리가 가능하다.

delegate 키워드를 사용.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
 
namespace ToolboxTestApp1
{
    class Program
    {
        // 위임이 무엇인고??
        public delegate int Printer(string msg); // 함수 포인터 처럼 함수 바디는 필요 없다.
 
        public static int Printer_My1(string msg)
        {
            System.Console.WriteLine("Printer_My1 = " + msg);
            return 1;
        }
 
        public static int Printer_My2(string msg)
        {
            System.Console.WriteLine("Printer_My2 = " + msg);
            return 2;
        }
 
        static void Main(string[] args)
        {
            Printer _printer = new Printer(Printer_My1);
            _printer += new Printer(Printer_My2); // += 연산자를 통해서 다중 위임 처리.
 
            _printer("한가한가~"); // _printer 에 위임된 프린터가 동작한다.
        }
    }
}



반응형
반응형

http://pullthelever.tistory.com/332






- Case 1

class A
{
   b;       //당연히 된다.
   B.c;    //클래스 B 안에 클래스 C가 public이므로 가능하다.
                 //public이 아니면 아래와 같은 오류가 나온다.
                 //오류 CS0122: 보호 수준 때문에 '_namespace.B.C'에 액세스할 수 없습니다.

}

class B
{
    public class C//public말고도 private, protected도 가능하다.
    {
       //...
    }
}



- Case 2
class A          //기본으로 internal이다.
{
   //...
}

public class B//private, protected는 못 오고 internal, public만 올 수 있다.
{
   public a;
// 오류 CS0052: 일관성 없는 액세스 가능성:
// '_namespace.A' 필드 형식이 '_namespace.B.a' 필드보다 액세스하기 어렵습니다.

   public func1() { return a; }
// 오류 CS0050: 일관성 없는 액세스 가능성:
// '_namespace.A' 반환 형식이 '_namespace.B.func1()' 메서드보다 액세스하기 어렵습니다.

   public void func2(a) { this.a = a; }
// 오류 CS0051: 일관성 없는 액세스 가능성:
// '_namespace.A' 매개 변수 형식이 '_namespace.B.func2(_namespace.A)' 메서드보다
//  액세스하기 어렵습니다.
}


- 이유
   A는 internal로 외부로 공개되지 않았는데 외부로 공개하는 B에서 A를 외부로 공개하려고 하니 오류가 발생한다.

- Case 2 처방전
첫 번째 방법)
   class 를 public class A로 바꾼다

두 번째 방법)
   public class B를 class B로 바꾼다

세 번째 방법)
   public a, public func1(), public void func2(a) 
   a, func1(), void func2(a) 로 바꾼다

- public과 internal란
public으로 선언된 경우 다른 어셈블리에서도 접근할 수 있다.
internal으로 선언된 경우 동일한 어셈블리의 파일 내에서만 접근할 수 있다.
아무것도 안 넣으면 internal이다.


반응형
반응형
http://cjh7163.blog.me/220444677611



일반적으로 생성자는 클래스의 인스턴스 필드를 초기화하려고 사용한다.
그렇다면 정적 생성자는 어떤 용도로 사용할까?

당연히 클래스의 정적 필드를 초기화할 때 사용한다. 아래의 예제를 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 
using System;
namespace _static_constructor
{
    class Student
    {
        static public int Id { get; private set; }
        public Student()
        {
            Console.WriteLine("Student ID + 1");
            ++Id;
        }
        static Student()
        {
            Console.WriteLine("Set Student ID : 0");
            Id = 0;
        }
    }
    class MyApplication
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Student ID : {0}", Student.Id);
            Student std1 = new Student();
            Student std2 = new Student();
            Console.WriteLine("Student ID : {0}", Student.Id);
        }
    }
}
 
cs

 


위의 소스코드를 보면 생성자가 두 가지가 있는데, 하나는 인스턴스 생성자이고 다른 하나는 정적 생성자이다.

코드는 어떤 동작을 하겠는가?


먼저 Student 클래스의 정적 필드 Id를 출력하고, 뒤에 Student 인스턴스를 두개 생성하여 인스턴스 생성자가 두번 호출되고

Id는 1씩 두번 증가하게 될 것이다. 그리고 마지막으로 Id를 출력한다.


인스턴스 생성자는 클래스 인스턴스가 생성될 때 호출된다. 그렇다면 정적 생성자는 언제 호출될까?


일단 프로그램을 먼저 실행해보겠다.




Student 클래스의 정적 필드 Id를 출력하기 전에 정적 생성자가 호출되어 "Set Student ID : 0" 문자열을 출력하는 것을 볼 수 있다. 그렇다면 프로그램이 시작되면 자동으로 정적 생성자가 호출되는 것일까?

메인 메소드의 가장 윗 부분에 "break"라는 문자열을 출력하도록 코드를 추가하였다.




정적 생성자가 "break" 문자열이 출력된 다음에 호출되었다. 그렇다면 프로그램이 시작되면 자동으로 호출되는 것은 아니라는 것이다. 그러면 무엇에 의하여 정적 생성자가 호출 되는 것일까? 메인 메소드만 떼어내서 올려보겠다.


 

1
2
3
4
5
6
7
8
        static void Main(string[] args)
        {
            Console.WriteLine("break");
            Console.WriteLine("Student ID : {0}", Student.Id); 00
            Student std1 = new Student();
            Student std2 = new Student();
            Console.WriteLine("Student ID : {0}", Student.Id);
        }
cs


3번줄과 4번줄 사이에서 정적생성자가 호출되었다. 3번줄은 단순히 문자열을 출력하는 문장이므로 정적 생성자 호출과 전혀 연관성이 없음을 알 수 있을 것이다. 4번줄을 살펴보자. 여기서 문자열에 클래스의 정적 필드를 출력하는 것을 확인할 수 있다. 

이것으로 정적필드에 접근하려고 하면 먼저 정적 생성자가 생성된다는 것을 알 수 있다.

위의 코드에서 4번줄을 지우면 아래와 같은 결과를 볼 수 있다.




정적 필드에 접근하려고 할 때 뿐만아니라 인스턴스를 생성할 때도 먼저 정적 생성자가 호출된 뒤 인스턴스 생성자가 호출되는 것을 볼 수 있다. 또, 정적 생성자는 클래스 당 단 한번만 호출된다.


정적 생성자(static constructor)에 대하여 정리하면 다음과 같다.


1) 클래스의 정적필드에 접근하기 직전에 호출된다.

2) 클래스의 인스턴스를 생성하기 직전에 호출된다.

3) 모든 클래스의 정적 생성자는 최초 한번만 호출된다.


반응형
반응형

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace TestE
{


    class Employee
    {
        public string _name;
        public Employee(string name)
        {
            this._name = name;
            Console.Write ("Employee.CalculatePay:\n\t");
            CalculatePay ();
        }
        public virtual void CalculatePay()
        {
            Console.WriteLine ("Employee.CalculatePay called for {0}", _name);
        }
    }

    class SalariedEmployee : Employee
    {
        public decimal _salary;    
        public SalariedEmployee(string name, decimal salary) : base(name)
        {
            this._salary = salary;
            Console.Write ("SalariedEmployee.CalculatePay:\n\t");
            CalculatePay ();
        }
        public override void CalculatePay()
        {
            Console.WriteLine ("{0}, SalariedEmployee.CalculatePay, salary={1:C}", _name, _salary);
        }
    }

    class ContractEmployee : Employee
    {
        public double _rate;
        public ContractEmployee(string name, double rate) : base(name)
        {
            this._rate = rate;
            Console.Write ("ContractEmployee.CalculatePay:\n\t");
            this.CalculatePay ();

        }

        public override void CalculatePay()
        {
            Console.WriteLine ("{0}, ContractEmployee.CalculatePay, salary={1:C}", _name, _rate);
        }
    }

    class Program {
        static void Main(string[] args)
        {

            Employee[] employee = new Employee[2];
            employee[0] = new ContractEmployee("Ada" +
                "m Barr"123.45);

            Console.WriteLine ("");


            employee[1] = new SalariedEmployee(
                "Max Benson"67890m);

        }
    }
}



c++ 과는 다른 결과를 보인다, 생성자가 호출된 클래싀의 함수가 불리지 않고 virtual 로 선언된 경우 자식 함수가 불리게 된다




Employee.CalculatePay:

Adam Barr, ContractEmployee.CalculatePay, salary=₩0

ContractEmployee.CalculatePay:

Adam Barr, ContractEmployee.CalculatePay, salary=₩123


Employee.CalculatePay:

Max Benson, SalariedEmployee.CalculatePay, salary=₩0

SalariedEmployee.CalculatePay:

Max Benson, SalariedEmployee.CalculatePay, salary=₩67,890





반응형
반응형
https://kloudstyle.wordpress.com/2012/09/05/c-%EC%83%81%EC%86%8D%EB%B0%9B%EC%9D%80-%ED%9B%84-new-override-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EC%98%88%EC%A0%9C/



[C#] 상속받은 후 new , override 차이점 예제


public class BaseClass

{

    public virtual void Foo() { Console.WriteLine("BaseClass.Foo"); }

}

 

public class Overrider : BaseClass

{

    public override void Foo() { Console.WriteLine("Overrider.Foo"); }

}

 

public class Hider : BaseClass

{

    public new void Foo() { Console.WriteLine("Hider.Foo"); }

}

 

static void Main(string[] args)

{

    Overrider over = new Overrider();

    BaseClass b1 = over;

    over.Foo(); // Override.Foo

    b1.Foo();   // Override.Foo

 

    Hider h = new Hider();

    BaseClass b2 = h;

    h.Foo();    // Hider.Foo

    b2.Foo();   // BaseClass.Foo

}



override 메소드로 구현하게되면 부모클래스에서 호출하면 자식클래스의 오버라이드함수를 수행한다.
new 메소드로 구현하게되면, 기존의 부모와 별개의 함수이므로, 부모클래스에서 호출하면 부모클래스의 원래 함수를 실행하고, 자식클래스에서는 자식클래스의 함수를 실행한다.


출처: C# 5.0 in a nut shell


반응형
반응형

http://soulduo.tistory.com/77


숫자 데이터 형식에 대해 상한 값과 하한 값이 고정되어 있다.

(이는 MaxValue / MinValue 로 확인 가능하다.)

프로그래머의 실수로 상한 값과 하한 값을 범위를 넘겨 값을 활당할 경우

각각 '오버플로우'와 '언더플로우' 상황이 발생한다.

CLR에서는 두 경우 모두 '오버플로우'로 통칭한다.

왜 '가 발생한다'로 표기하지 않고 '상황이 발생한다.' 라고 표현했는지는

기초를 충실히 했다면 간단한 설명으로 이해가 가능할 것이다.

이는 byte의 최대 값이 255이라는 것을 생각하고 다음의 경우를 보자.

byte b1 = 100;
byte b2 = 250;
byte b3 = (byte) b1 + b2;

이 때 b3의 값은 얼마일까?

b3에는 넘치고 남는 값만이 남게 된다. (350 - 256 = 94)

상황이 발생한다는 것은 논리 에러만이 존재하며 예외 상황이 발생하지 않기 때문에

표현한 것이다.

간단한 연산에 대해서는 프로그래머가 모두 관리 가능하겠지만

어째건 모든 프로그래머는 실수를 하기 마련이다.

(존경 받는 '찰스 페졸드' 같은 사람도 어떤 부분에서든 실수를 하고)

(이를 바로 잡을 것이다.)

아무튼 이러한 상황을 프로그래밍 차원에서 규제할 수 있다.

이 때 사용되는 코드가 checked이다.

다음과 같이 코드를 작성하게 되면 오버 플로우 상황에서

System.OverflowException 예외가 발생하게 된다.


try
{

byte b3 = checked((byte)(b1 + b2));
}
catch(OverflowException e)
{
Console.WriteLine(e.Message);
}

비쥬얼 스튜디오의 경우 프로젝트 속성 페이지의 산술 연산 오버플로/언더플로 확인

옵션을 'True'로 설정함으로 프로젝트 단위에서 예외 발생 여부를 확인할 수 있다.

하지만 모든 상황에서 예외 처리를 하고 싶지 않을 때가 있을 것이다.

이럴 때 'unchecked' 키워드를 사용하게 된다.

unchecked
{
byte b3 = (byte)(b1 + b2);
}

모든 오버플로우 체크 중에 다음의 연산에서는 예외 상황을 발생시키지 않으며

(350 - 256 = 94)의 연산을 수행하여 b3는 94의 값을 가지게 된다.


반응형
반응형

http://www.gamedevforever.com/322



C# Boxing과 Unboxing

프로그래밍 2015/01/30 09:43
Posted by 친절한티스

요즘 유니티를 이용해 C#으로 코딩을 하시는 분들이 많은데, 간혹 면접을 보다보면 Boxing과 Unboxing에 대해 제대로 이해하지 못하는 분들이 많더군요. 이를 C/C++의 캐스팅 같은 것으로 생각하고 마구잡이로 사용하시는 분들이 많은듯 합니다. 하지만 C/C++의 캐스팅과 다르게 C#의 Boxing은 그 과정에서 개체 할당이 일어 나기 때문에 성능 이슈가 생길수 있습니다.


  1. int num1 = 123;  
  2. object obj = num1;      // boxing  
  3. int num2 = (int)obj;    // unboxing  


C#에서 사용되는 모든 타입들은 object 에서 직/간접적으로 상속을 받게 됩니다. 즉, 최상위 부모 클래스 같은 존재지요. 이것이 C/C++에서 였다면, 위의 num1에서 obj로의 대입은 단순 업캐스팅으로 변환되는 거기 때문에 큰 문제는 없을 겁니다. 하지만 C#에서는 다릅니다. C#에서는 이를 Boxing이라 부르며 아래와 같이 힙 Heap에 새로운 개체를 할당하고 그 곳에 값을 복사하게 됩니다. 



C++ 코드로 보자면 아래와 같은 상황인겁니다.


  1. int num1 = 123;  
  2. int *obj = new int;  
  3. (*obj) = num1;  

이 때문에 MSDN에서도 Boxing, Unboxing에 대해 아래와 같이 조언하고 있습니다.

  • System.Collections.ArrayList 같은 제네릭이 아닌 컬렉션 클래스의 예와 같이 많은 수의 boxing이 필요한 경우에는 값 형식을 사용하지 않는 것이 좋습니다. System.Collections.Generic.List 같은 제네릭 컬렉션을 사용하면 값 형식의 boxing을 방지할 수 있습니다. boxing 및 unboxing 과정에는 많은 처리 작업이 필요합니다. 값 형식을 boxing할 때는 완전히 새로운 개체가 만들어져야 하며, 이러한 작업은 간단한 참조 할당보다 최대 20배의 시간이 걸립니다. unboxing을 할 때는 캐스팅 과정에 할당 작업보다 4배의 시간이 걸릴 수 있습니다.


반대로 Unboxing의 경우 Boxing과는 다르게 대입하려는 타입을 명시적으로 지정해주어야 합니다. Bxoing 되어있는 타입과 명시한 타입이 같으면, 해당 객체의 값을 복사합니다.



C#은 C/C++에 비해 타입에 엄격하기 때문에 Boxing 타입과 다른 타입으로 Unboxing을 시도하면 InvalidCastException 같은 에러를 냅니다.


참조 : MSDN Boxing 및 Unboxing


반응형
반응형

https://msdn.microsoft.com/ko-kr/library/67ef8sbd.aspx


C# 프로그래밍 가이드

이 단원에서는 C# 언어의 주요 기능 및 C#에서 .NET Framework를 통해 액세스할 수 있는 기능에 대한 자세한 정보를 제공합니다.

이 단원에서는 독자가 C# 및 일반적인 프로그래밍 개념에 대해 잘 알고 있다고 가정합니다. 프로그래밍이나 C#에 처음 입문하는 사용자는 C# 개발자 센터에서 처음 시작할 때 도움이 되는 많은 자습서, 샘플 및 비디오를 찾을 수 있습니다.

특정 키워드, 연산자 및 전처리기 지시문에 대한 자세한 내용은 C# 참조를 참조하십시오. C# 언어 사양에 대한 자세한 내용은 C# 언어 사양을 참조하십시오.


반응형
반응형

http://gcstudy.tistory.com/60

deprecated declaration (VC++)

오랫만의 포스팅 이군요.


deprecated 선언에 대한 간단한 얘기를 좀 남겨볼까 합니다.


보통 C++ 를 배우고 Visual C++ 을 IDE 로 채택해서 작업을 해나가는 프로그래머들이


언뜻 언뜻 CRT 의 함수 중 보안 취약성으로 인해서 C4995 경고를 만나게 되면서


deprecated 에 대해서 인지하게 되지 않나 싶은데요.


msdn (http://msdn.microsoft.com/en-us/library/044swk7y.aspx을 보면 설명이 나오지만


나타내고자 하는 바는 단순합니다. 


deprecated 로 선언된 함수나 타입을 사용할 때 사용자에게 조심하라는 말을 전달하고 싶은 것이죠.


그런데, 프로그래밍을 시작한지 얼마 안되는 시점에서는 이 deprecated 선언의 필요성에 대해서 잘 느끼지 못하지 않나 싶습니다.


그래서 간단한 하나의 예정도를 적어 보자면..


모종의 변환 행렬을 연산해서 3D 공간 상의 Object 의 위치를 얻어 내는 함수가 있다고 가정 합시다.


개발이 진행 되고 서비스를 시작한 뒤 점차 추가적인 컨텐츠를 붙여나가던 도중에 이 함수가 특정 상황에서


내부적으로 행렬 연산을 잘 못하게 되는 버그가 발견 되었다고 칩시다.


이 경우에 가장 첫 번째로 생각하게 되는 솔루션은 해당 함수의 버그를 수정한다 이겠지만 ..


이렇게 할 경우 의도치 않은 상황이 발생할 수 있습니다.


다른 누군가가 이 함수를 가져다 사용하면서 함수의 버그를 수정하기 보다는 잘 못된 수치 만큼을 보정 작업을 추가로


삽입하는 식으로 사용하고 있을지도 모르기 때문입니다.


이런 경우에 택할 수 있는 선택지 중의 하나가 deprecated 선언으로 (이것도 나름의 문제는 있긴 하지만..)


버그가 내재된 기존의 함수를 deprecated 선언을 시키고 새로운 함수를 작성하고 이 후로는 그것을 사용하도록 유도하는 것입니다.


예를 들면,


__declspec(deprecated("리비전 넘버 100 이후로는 이 함수를 사용하지말고 foo_ver2 를 사용하세요."))

void foo() { }


이런식으로요.


반응형
반응형

http://mwultong.blogspot.com/2006/12/c-hex-16-10-hex-string-to-int-number.html

십육진수 헥사 문자열을, 숫자(정수)로 변환 예제


소스 파일명: 0.cpp

#include <stdio.h>
#include <stdlib.h>


int main(void) {

  // 헥사 문자열을 long 으로
  char *s = "0x7FFFFFFF";
  long n = strtol(s, NULL, 16);
  printf("%d\n", n);
  // 출력 결과: 2147483647



  // 헥사 문자열을 unsigned long 으로
  char *s2 = "0xFFFFFFFF";
  unsigned long n2 = strtoul(s2, NULL, 16);
  printf("%u\n", n2);
  // 출력 결과: 4294967295



  // 헥사 문자열을 64-bit int 로
  char *s3 = "0x7FFFFFFFFFFFFFFF";
  __int64 n3 = _strtoi64(s3, NULL, 16);
  printf("%I64d\n", n3);
  // 출력 결과: 9223372036854775807



  // 헥사 문자열을 unsigned 64-bit int 로
  char *s4 = "0xFFFFFFFFFFFFFFFF";
  unsigned __int64 n4 = _strtoui64(s4, NULL, 16);
  printf("%I64u\n", n4);
  // 출력 결과: 18446744073709551615

  return 0;
}


반응형
반응형

http://blog.naver.com/sorkelf/40138272917



C++11 강력해진 Enumeration과 전방선언 Strongly typed enumerations


Strongly typed enumerations


이전 C++에서의 Enumeration은 안전한 타입이 아니었다. 따로 enum값을 취하려고 해도 결과적으로는 Int형이기 때문에 얼마든지 캐스팅이 가능한 형태를 띄고 있었다.


enum Color { ClrRed, ClrBlue, ClrYellow, ClrGreen, ClrBlack };

enum Alert { AltGreen, AltYello, AltRed };


bool is_danger(Alert alert)

{

    return alert == ClrRed; // OK...다른 enum형도 비교 가능

}


영역부분에선

enum Color { Red }; 
enum Alert { Red }; // 에러

C++0x에서는 [enum class / enum struct] 형식이 추가 되어 위와 같은 문제를 해결할 수 있게 되었다.

enum class Enumeration 
{ 
     Val1, 
     Val2, 
     Val3 = 100,
     Val4 /* = 101 */ 
};


이 형태의 enumeratrion은 타입안전을 보장하며 enum 클래스 값은 명시적으로 int형으로 캐스팅 할 수 없다.

그러므로 이들은 여타 다른 enum값이나 int 형과 비교 할 수 없다 ( 컴파일 에러출력)

또한, enum 클래스의 기본타입은 기본값은 int형이나 아래와 같이 명시적으로 다른 타입을 지정 할 수도 있다.


enum class Enum2 : unsigned int { Val1, Val2};


또한 이전 처럼 클래스가 아닌 기존 enum을 사용할 수 잇으며 처음 기본 값을 지정해줄 수도 있다


enum Enum3 : unsigned long {Val1 = 1, Val2};


C++0x에서는 enum의 크기(size) 만큼 명시적으로든 암시적으로든 선언이 가능하게 되었다.

enum Enum1; //C++, C++0x 어느쪽에서도 컴파일 에러이다 (정의되어있지 않음) 
enum Enum2 : unsigned int; //C++0x에선 가능, 기본 유형을 명시적으로 지정했음 
enum class Enum3; //C++0x에선 가능, 기본 타입은 Int 형 
enum class Enum4 : unsigned int; //C++0x 에서 가능. 
enum Enum2 : unsigned short; //C++0x에서 불가, Enum2가 기본타입을 이미 위에서 명시하고 있음





Enum Class 전방선언




C++0x에서는 struct나 class 처럼 enum도 전방선언이 가능하게 되었다


아래와 같은 헤더파일이 있다고 할때

// Color.h

enum Color

    .... 

};

void draw(Color& color);


draw 함수의 선언에서는 color내의 enum형을 필요하지 않지만

C++03에서는 enum을 전방선언하는것이 불가능했기 때문에

Color의 enum형을 변경하려면 관련된 모든 파일을 재컴파일을 해야 했다


C++0x에서는 enum의 전방선언이 가능하게 되어

아래와 같이 쓰는것이 가능해졌다

// Color.h 

enum Color int; 


void draw(Color& color);

// Color.cpp 

enum Color : int 
{
    ... 
}; 

void draw(Color& color) 
    ... 
}

위와 같이 쓰면 Color의 enum형을 변경한다 해도

재컴파일은 Color.cpp만 하면된다


Enum의 전방선언을 하려면 

기본이 되는 형 (ex : int 형)을 지정해야 한다


enum E; //에러 
enum E : int//OK

Enum의 재선언을 할때에는 기본형이 같아야 한다


enum E : int
enum E : short// 에러!! 기본형이 일치하지 않음 
enum E : int// OK


또, enum의 전방선언은 영역이 존재하는 enum값인 enum클래스에서도 적용되어 있다

enum class E : int; //OK


클래스나 네임스페이스에서 선언했단 enum도 스코프를 지정해서 정의할 수 있다

struct S 
{ 
    enum E : int; 
    E e; 
}; 

enum S::E : int 
{
    ... 
};



반응형
반응형

http://cafe.naver.com/dxgameprogramming/1443






http://cafe.naver.com/mathclub/84160



 

수학에서 봤을 때.. 무한 소수란 것이 있습니다.

예를 들어서

1/3 = 0.333333......

즉 3이 연속해서 나타나죠.

이 3은 끝없이 나타나기 때문에 무한소수라고 합니다.

 

컴퓨터에서는 아쉽게도 유리수형태의 수를 표현하는 자료형이 없습니다.

컴퓨터에서는 부동소수점(Floating point number)이란 자료형이 있죠.

 

부동소수점이라는 것은 소수점 위치를 옮겨서 잡는다는 뜻을 가지고 있습니다.

1.M 이란 소수가 있다면, 이 소수점 위치를 왼쪽 또는 오른쪽으로 지수부(E)로 옮기게 됩니다.

 

소수형태의 표현이므로 컴퓨터에서 표현할 수 없는 유리수들이 많겠죠.

 

컴퓨터는 이진수 체계를 가지고 있습니다.

그러다보니 컴퓨터에서 표현할 수 없는 유리수는 우리가 수학에서 사용하는 것보다 더 많습니다.

 

0.2  를 표현하고자 합니다.  이 수는 유한소수입니다만, 컴퓨터에서는 무한소수가 됩니다.

십진법 체계에서는 분모가 2 또는 5라는 소인수만 가져야죠?  왜냐하면 2x5 = 10 이기 때문이죠.

이진법 체계에서는 분모가 2라는 소인수만 가져야 합니다.  2는 소수이기 때문이죠.

 

0.2 를 이진법으로 표현할려면.. 무한소수가 됩니다.  왜냐하면 1/5 = 0.2 이기 때문에 분모에 5라는 소인수가 존재하죠.

0.2 를 이진법으로 표현할 때에는 정수부를 무조건 1로 만들어야 합니다.

0.2 * 8 = 1.6 이죠.  그럼 여기서 출발을 합니다.

1.6을 이진법으로 표현하면..

1.100110011001....

과 같이 소수부가 1001 이 반복하게 됩니다.  (너무나도 당연하겠지만 분모가 5이므로 4의 약수로 순환고리를 갖습니다.)

 

그런데 무한한 메모리를 가진 것이 아니기 때문에.. 소수부를 무한히 표현할 수 없습니다.

그래서 우리는 여기서 오차가 발생합니다.  이것을 Round off error 라고 하며, 우리말로 반올림 오차라고 합니다.

 

이 값은 하나의 숫자 상태에서는 중요하지 않습니다.  유효자리수 대비 2^-23 이라는 아주 작은 숫자(백만분의 1 오차)이기 때문이죠.

하지만 이 값에 숫자들을 곱하거나 더하거나 한다면 반올림 오차는 증가하게 됩니다.

 

프로그램을 할 때에는 이 반올림 오차에 대해서 충분하게 고려를 해주어야 합니다.

 

보통 부동소수점 연산에서는 == 을 사용하지 않습니다.  반올림 오차 때문이죠.

x == 0.0 대신에 우리는 x < 0.00001 && x > -0.00001 과 같이 합리적인 형태로 검사를 합니다.


반응형
반응형

http://javawoo.tistory.com/30



구조체 메모리 저장방식 #pragma pack

분류없음 2011/04/23 17:24
- 클래스(구조체)의 바이트 패딩 -
멤버 변수를 메모리에서 CPU 레지스터로 한번에 읽을 수 있도록
CPU 레지스터의 읽기 블록에 맞춰 정렬하는 컴파일러의 최적화 작업
컴파일러가 패딩을 하지 않아 레지스터가 읽는 블록의 경계에 걸쳐 멤버 변수가 생긴다면
메모리를 읽을 때 두개의 블록을 읽어는 문제가 발생
CPU 레지스터는
32비트 운영체제일때 4바이트
64비트 운영체제일때 8바이트 단위로 메모리를 읽는다

구조체를 4바이트 단위로 끊어주는것을 "바이트 패딩" 이라고 한다.
 

구조체는 메모리에 어떤 식으로 저장될까
다음과 같은 소스를 보자.
 
  1. #include <stdio.h>   
  2.   
  3. typedef struct _TEST{   
  4.     char cData;   
  5.     short sData;   
  6.     int iData;   
  7. }TEST;   
  8.   
  9. int main()   
  10. {   
  11.     TEST TData={0,};   
  12.   
  13.     printf("cData size : %d\n"sizeof(TData.cData));   
  14.     printf("sData size : %d\n"sizeof(TData.sData));   
  15.     printf("iData size : %d\n"sizeof(TData.iData));   
  16.     printf("TData size : %d\n"sizeof(TData));   
  17.        
  18.     return 0;   
  19. }  


TEST 구조체 변수인 TData는 char형 데이터(1byte), short형 데이터(2byte), int형 데이터(4byte)를 가지고 있으므로 1+2+4=7byte의 크기를 가질 것 처럼 보인다. 하지만 이 소스를 컴파일하고 실행을 해보면 다음과 같은 결과가  나온다.



분명히 cData(1) + sData(2) + iData(4) = 7임에도 불고하고 TData의 크기는 8바이트라고 하니 참 이상한 일이다.

이는 현재 우리가 쓰는 32비트 컴퓨터에서 32비트 컴파일러를 사용하였기 때문에 32비트 즉, 4바이트로 데이터를 처리하는 것에 가장 최적화되어 있기 때문에 데이터를 4바이트 공간으로 저장하기 때문이다.

이 TData란 구조체는 8바이트에 다음과 같이 저장되어 있다.

cData
??
sData
sData
iData
iData
iData
iData

cData를 저장하고, 4바이트중에 3바이트가 남아있기 때문에 sData를 3바이트 중에 2바이트의 공간에 저장하고,
iData를 저장하려 하니 1바이트밖에 남아있지 않기 때문에 4바이트의 공간을 따로 만들어 저장하게 되는 것이다.

그럼 이제 위의 소스에서 변수 선언의 순서를 한 번 바꿔 보자.

 
  1. typedef struct _TEST{   
  2.     char cData;   
  3.     int iData;   
  4.     short sData;   
  5. }TEST;  


변수 선언의 순서를 바꿨을 뿐인데 신기하게도 같은 구조체의 크기가 8에서 12로 늘어나버렸다.
이 TData 구조체 변수는 다음과 같이 저장되어 있을 것이다.

cData
(1byte)
empty
(3byte)
sData
(2byte)
empty
(2byte)
iData
(4byte)

이처럼 컴파일러는 4바이트에 맞춰서 데이터를 저장하는 것을 볼 수 있다. 이것을 막으려면 어떻게 해야할까.

이것을 해결하려면 #pragma pack() 이라는 전처리어를 사용하면 된다.
구조체 하나를 더 추가한 다음 소스를 보자.

 
  1. #include <stdio.h>   
  2.   
  3. typedef struct _TEST{   
  4.     char cData;   
  5.     int iData;   
  6.     short sData;   
  7. }TEST;   
  8.   
  9. #pragma pack(1)   
  10. typedef struct _TEST2{   
  11.     char cData;   
  12.     int iData;   
  13.     short sData;   
  14. }TEST2;   
  15.   
  16. int main()   
  17. {   
  18.     TEST TData={0,};   
  19.     TEST2 TData2={0,};   
  20.   
  21.     printf("TData size : %d\n"sizeof(TData));   
  22.     printf("TData2 size : %d\n"sizeof(TData2));   
  23.        
  24.     return 0;   
  25. }  


#pragma pack(1)에서 1은 1바이트 단위로 저장하겠다는 것이다. 따라서 TData와 TData2의 내용물은 같으나 크기는 다른 것을 확인할 수 있다.

 그렇다면, 왜 모두 1바이트로 해서 메모리의 낭비가 없도록 하지 않는 것일까?
 그것은, 아까도 이야기하였듯이 32비트 CPU에서는 4바이트(32비트)의 단위로 데이터를 처리하는 것이 가장 빠르게 때문이다. 즉, #pragma pack(1) 이라고 선언해놓고 원래대로 돌려놓지 않는다면 속도저하의 문제가 생길 수 있다.
 따라서, 위의 소스에서 구조체 선언이 끝나는 부분에 #pragma pack(4)라고 선언해주어 할 것이다.

 하지만, 여기에도 문제가 있다.
 만약, 이 소스를 32비트의 PC가 아닌 다른 CPU가 장착된 장비에서 컴파일하게 된다면 어떻게 될 것인가. 예를 들면 임베디드 시스템 같은 8~16비트 CPU에서 말이다.
 소스를 일일히 찾아서 CPU에 맞게 고쳐주고 다시 컴파일해야 되는 불편함과 어려움이 생기게 된다.

 이럴때를 위해서 좀 더 우아하게 쓰는 코드가 있다.

 
  1. #pragma pack(push, 1)   
  2. typedef struct _TEST2{   
  3.     char cData;   
  4.     int iData;   
  5.     short sData;   
  6. }TEST2;   
  7. #pragma pack(pop)  


 기존의 바이트를 스택에 push하고 1바이트 단위로 처리한다음 끝나는 부분에 원래의 바이트 단위를 pop해주는 코드이다. 보통은 이렇게 사용하면 되겠다.


 

아래와 같은 코드를 사용하면 구조체 크기는 1바이트가된다.

  1. #pragma pack(push, 1)   
  2. typedef struct DATA{   
  3.     char cData;      
  4. }DATA;   
  5. #pragma pack(pop)  


반응형
반응형

http://www.codeproject.com/Articles/124644/Basic-Understanding-of-Tree-View-in-WPF


Basic Understanding of Tree View in WPF

3 Nov 2010
This article explains different ways to show contents in the Tree View control.

Introduction

This article describes the use of TreeView control provided by WPF. It will give you a knowledge to create simple Tree, customization, Template and Binding. It mainly focuses on how to show contents in the tree view. This article will help you to understand the basics of tree view and also gives you deep knowledge to show content on tree according to your requirement.

I had to use tree view in one of my projects where I had to show image and text as most of tree has in windows. This problem started my journey to learn features provided by WPF. At the start of my journey, I found many difficulties and sometimes I said Windows application contains more user friendly controls to work with, but with the passage of time I found WPF controls more user friendly.

This article will cover the following 6 main areas:

Create Simple Tree

If you want to create a simple tree then WPF provides you an easy way draw tree. Just add TreeView control on your page and add items in either using XAML or from code behind.

Using XAML

You can easily create a tree using XAML.

 <TreeView>
    <TreeViewItem Header="North America">
        <TreeViewItem Header="USA"></TreeViewItem>
        <TreeViewItem Header="Canada"></TreeViewItem>
        <TreeViewItem Header="Mexico"></TreeViewItem>
    </TreeViewItem>
    <TreeViewItem Header="South America">
        <TreeViewItem Header="Argentina"></TreeViewItem>
        <TreeViewItem Header="Brazil"></TreeViewItem>
        <TreeViewItem Header="Uruguay"></TreeViewItem>
    </TreeViewItem>
 </TreeView>

Using code

If you want to populate tree from code behind, then simply place your tree on form and add tree item according to your tree hierarchy.

 <TreeView Name="tvMain">
 </TreeView>
 TreeViewItem treeItem = null;
         
 // North America 
 treeItem = new TreeViewItem();
 treeItem.Header = "North America";

 treeItem.Items.Add(new TreeViewItem() { Header = "USA" });
 treeItem.Items.Add(new TreeViewItem() { Header = "Canada" });
 treeItem.Items.Add(new TreeViewItem() { Header = "Mexico" });

 tvMain.Items.Add(treeItem);

Customize Tree

If you want to add some other controls with the content e.g. checkbox, image, etc., then you can easily design your tree without any big effort. You just need to customize the HeaderTemplate of the TreeViewItem. You can also create class derived from TreeViewItem and change its Header according to your requirement.

Using XAML

For customizing the Tree item, simply change item’s Header.

 <TreeView >
    <TreeViewItem >
        <TreeViewItem.Header>
            <StackPanel Orientation="Horizontal">
                <Border Background="Green" Width="8" Height="12" 
                        BorderBrush="#00000000"></Border>
                <Label Content="North America"></Label>
            </StackPanel>
        </TreeViewItem.Header>

        <!-- Child Item -->

        <TreeViewItem>
            <TreeViewItem.Header>
                <StackPanel Orientation="Horizontal">
                    <Image Source="../Images/usa.png"></Image>
                    <Label Content="USA"></Label>
                </StackPanel>
            </TreeViewItem.Header>
        </TreeViewItem>
    </TreeViewItem>
 </TreeView>

Using Code

If you want to create header from code behind, then WPF will not disappoint you. You can change header template very smartly.

 private TreeViewItem GetTreeView(string text, string imagePath)
 {
    TreeViewItem item = new TreeViewItem();

    item.IsExpanded = true;

    // create stack panel
    StackPanel stack = new StackPanel();
    stack.Orientation = Orientation.Horizontal;

    // create Image
    Image image = new Image();
    image.Source = new BitmapImage
		(new Uri("pack://application:,,/Images/" + imagePath));

    // Label
    Label lbl = new Label();
    lbl.Content = text;


    // Add into stack
    stack.Children.Add(image);
    stack.Children.Add(lbl);

    // assign stack to header
    item.Header = stack;
    return item;        
 }

Using overriding TreeViewItem

You can also customize TreeViewItem by writing a new derived class for custom item. It is also pretty easy. Just create header template and assign it to Header property if TreeViewItem.

 public class ImageTreeViewItem : TreeViewItem
 {
    #region Data Member

    Uri _imageUrl = null;
    Image _image = null;
    TextBlock _textBlock = null;

    #endregion

    #region Properties

    public Uri ImageUrl
    {
        get { return _imageUrl; }
        set
        {
            _imageUrl = value;
            _image.Source = new BitmapImage(value);
        }
    }

    public string Text
    {
        get { return _textBlock.Text; }
        set { _textBlock.Text = value; }
    }

    #endregion

    #region Constructor

    public ImageTreeViewItem()
    {
        CreateTreeViewItemTemplate();
    }

    #endregion

    #region Private Methods

    private void CreateTreeViewItemTemplate()
    {
        StackPanel stack = new StackPanel();
        stack.Orientation = Orientation.Horizontal;

        _image = new Image();
        _image.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
        _image.VerticalAlignment = System.Windows.VerticalAlignment.Center;
        _image.Width = 16;
        _image.Height = 16;
        _image.Margin = new Thickness(2);

        stack.Children.Add(_image);

        _textBlock = new TextBlock();
        _textBlock.Margin = new Thickness(2);
        _textBlock.VerticalAlignment = System.Windows.VerticalAlignment.Center;

        stack.Children.Add(_textBlock);

        Header = stack;
    }

    #endregion
 }

Header Template

If the style of all the elements is the same, then it is better to create header template at once. Because the problem with the last example was for the same design, we add template for each tree item.

Using XAML

For creating general TreeViewItem item template, create Template resource at application level, window level or at control level resource. In this example, I have created resource at control level and set theTargetType=”TreeViewItem” and also set the “HeaderTemplate” property of the TreeViewItem.

 <TreeView Name="tvMain">
    <TreeView.Resources>
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="HeaderTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">                                 
                            <CheckBox Name="chk" Margin="2" Tag="{Binding}" >
			</CheckBox>
                            <Image  Margin="2"  Source="{Binding Converter=
			{StaticResource CustomImagePathConvertor}}"></Image>
                            <TextBlock Text="{Binding}"></TextBlock>
                        </StackPanel>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </TreeView.Resources>

    <TreeViewItem Header="North America" IsExpanded="True">
        <TreeViewItem Header="USA"></TreeViewItem>
        <TreeViewItem Header="Canada"></TreeViewItem>
        <TreeViewItem Header="Mexico"></TreeViewItem>
    </TreeViewItem>

    <TreeViewItem Header="South America"  IsExpanded="True">
        <TreeViewItem Header="Argentina"></TreeViewItem>
        <TreeViewItem Header="Brazil"></TreeViewItem>
        <TreeViewItem Header="Uruguay"></TreeViewItem> 
 </TreeView>

It is a very interested point here that I did not pass Image path for each country, but TreeView shows flag with each country. I achieved by writing custom converter CustomImagePathConverter.

  <Image  Margin="2"  Source="{Binding Converter=
	{StaticResource CustomImagePathConverter}}"></Image>     

Implement CustomImagePathConverter from IValueConverter. You can associate a value converter with binding. In this example, I am getting image path from the country name, as you can see in code.

 public class CustomImagePathConverter : IValueConverter
 {
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, 
                                    System.Globalization.CultureInfo culture)
    {
        return "../Images/" + GetImageName(value.ToString());
    }

    public object ConvertBack(object value, Type targetType, object parameter, 
                                    System.Globalization.CultureInfo culture)
    {
        return "";
    }

    #endregion

    private string GetImageName(string text)
    {
        string name = "";
        name = text.ToLower() + ".png";
        return name;
    }
 } 

Using Code

You can easily create template from code behind. FrameworkElementFactory provides you a facility to create templates. Let's see how can we achieve this exciting feature.

 private DataTemplate GetHeaderTemplate()
 {
    //create the data template
    DataTemplate dataTemplate = new DataTemplate();

    //create stack pane;
    FrameworkElementFactory stackPanel = new FrameworkElementFactory(typeof(StackPanel));
    stackPanel.Name = "parentStackpanel";
    stackPanel.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);

    // Create check box
    FrameworkElementFactory checkBox = new FrameworkElementFactory(typeof(CheckBox));
    checkBox.Name = "chk";
    checkBox.SetValue(CheckBox.NameProperty, "chk");
    checkBox.SetValue(CheckBox.TagProperty , new Binding());
    checkBox.SetValue(CheckBox.MarginProperty, new Thickness(2));
    stackPanel.AppendChild(checkBox);

    // Create Image 
    FrameworkElementFactory image = new FrameworkElementFactory(typeof(Image));
    image.SetValue(Image.MarginProperty, new Thickness(2));
    image.SetBinding(Image.SourceProperty, new Binding() 
		{ Converter = new CustomImagePathConverter() });
    stackPanel.AppendChild(image);

    // create text
    FrameworkElementFactory label = new FrameworkElementFactory(typeof(TextBlock));
    label.SetBinding(TextBlock.TextProperty, new Binding());
    label.SetValue(TextBlock.ToolTipProperty, new Binding());          
    stackPanel.AppendChild(label);

          
    //set the visual tree of the data template
    dataTemplate.VisualTree = stackPanel;

    return dataTemplate;
 } 

Simply assign this template to HeaderTemplate of each TreeViewitem.

 DataTemplate template = GetHeaderTemplate();

 foreach (WorldArea area in WorldArea.GetAll())
 {
    TreeViewItem item = new TreeViewItem();
    item.HeaderTemplate = template;
    item.Header = area.Name;

    .
    .
    .
    .
 }

Get selected checked items

You can easily get the child items from the template. Just for the example, I am showing you how to get the selected check boxes from the tree view. WPF manage control in hierarchical structure, you can access any child usingVisualTreeHelper class.

 private List<CheckBox> GetSelectedCheckBoxes(ItemCollection items)
 {
    List<CheckBox> list = new List<CheckBox>();
    foreach (TreeViewItem item in items)
    {
        UIElement elemnt = GetChildControl(item, "chk");
        if (elemnt != null)
        {
            CheckBox chk = (CheckBox)elemnt;
            if (chk.IsChecked.HasValue && chk.IsChecked.Value)
            {
                list.Add(chk);
            }
        }

        List<CheckBox> l = GetSelectedCheckBoxes(item.Items);
        list = list.Concat(l).ToList();
    }

    return list;
 }

 private UIElement GetChildControl(DependencyObject parentObject, string childName)
 {

    UIElement element = null;

    if (parentObject != null)
    {
        int totalChild = VisualTreeHelper.GetChildrenCount(parentObject);
        for (int i = 0; i < totalChild; i++)
        {
            DependencyObject childObject = VisualTreeHelper.GetChild(parentObject, i);

            if (childObject is FrameworkElement && 
		((FrameworkElement)childObject).Name == childName)
            {
                element = childObject as UIElement;
                break;
            }

            // get its child 
            element = GetChildControl(childObject, childName);
            if (element != null) break;
        }
    }

    return element;
 }

Custom Objects

WPF provides you many ways to populate tree. You can directly add your object as a TreeViewItem in the tree and WPF gives respect to your objects and display it as you want. You just need to tell him which field will be shown in item.

Using XAML

For populating custom object in tree, you just need to create template for your object. I usedHierarchicalDataTemplate for designing template.

 <TreeView Name="tvMain">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Path=Countries}">
            <StackPanel Orientation="Horizontal" Margin="4" Background="LightSeaGreen">
                <CheckBox Name="chk" Margin="2" Tag="{Binding Path=Name}" ></CheckBox>
                <Image  Margin="2" Source="{Binding Path=ImageUrl}" ></Image>
                <TextBlock Text="{Binding Path=Name}" Margin="2" >
                </TextBlock>
                <StackPanel.Effect>
                    <DropShadowEffect BlurRadius="2" Color="LightGray" 
			 Opacity=".2" ></DropShadowEffect>
                </StackPanel.Effect>
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>         
 </TreeView>

After creating template, you just need to add custom object from your code behind file, as you can see code below. I am just putting parent object in the tree. But when you will run this code, you will also see child countries are also being shown. The reason is that because I have define template in XAML for child items using ItemsSource="{Binding Path=Countries}".

 private void FillTree()
 {  
    foreach (WorldArea area in WorldArea.GetAll())
    {
        tvMain.Items.Add(area);        
    }
 }

Using Code

You can also create template for your object from code behind file, as we created in previous example. The tricky part here, how can we add custom objects in the hierarchical way? Because using XAML we can write create hierarchical template. We can also create hierarchical template using code behind, but in this example I am not doing that, I am achieving the solution from other way. This technique will give you a new way to work and you can implement it in other Items controls like ListViewListBox etc. But in the last example, I will create hierarchical template from code behind.

 private void FillTree()
 {
    tvMain.ItemTemplate = GetHeaderTemplate();
    tvMain.ItemContainerGenerator.StatusChanged += 
		new EventHandler(ItemContainerGenerator_StatusChanged);

    foreach (WorldArea area in _list)
    {
        tvMain.Items.Add(area);        
    }
 }

 void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
 {
    if (tvMain.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
    {
        foreach (WorldArea area in _list)
        {
            TreeViewItem item = 
		(TreeViewItem)tvMain.ItemContainerGenerator.ContainerFromItem(area);
            if (item == null) continue;
            item.IsExpanded = true;
            if (item.Items.Count == 0)
            {

                foreach (Country country in area.Countries)
                {
                    item.Items .Add(country);
                }
            }
        }
    }
 } 

As you can see in code after adding setting template, I have registeredtvMain.ItemContainerGenerator.StatusChanged event. ItemContainerGenerator generates the containers for each custom object. When we add custom object in the TreeView ItemContainerGenerator starts to generate container in separate thread. So we cannot get container in the next line after adding object. So you need to registerStatusChanged event, which fires after the status change and you can get container after that.

Data Binding

You can also bind your tree with any source as you can bind DataGridListView, etc. You just need to create a template for your items as you create in other binding controls.

Using XAML

Create your hierarchical template as you created in the previous example. You may need to add inner hierarchical template for different example. But it is working fine for my example.

 <TreeView Name="tvMain"  >
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Path=Countries}">

            <Grid Background="LightSkyBlue"  Margin="2" Width="100" Height="24">     
                <Image Margin="2" Width="32" Height="18" 
			Source="{Binding Path=ImageUrl}" 
		HorizontalAlignment="Right" 
               	VerticalAlignment="Center" ></Image>
                <TextBlock Margin="2" Text="{Binding Path=Name}" 
			VerticalAlignment="Center" FontWeight="Bold" />
            </Grid>

        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>            
 </TreeView>

Simply bind tree using ItemsSource property:

 private void BindTree()
 {
    tvMain.ItemsSource = WorldArea.GetAll(); 
 }

Using Code

For creating Hierarchical template from code behind simply create object of HierarchicalDataTemplate class and fill childs according to your requirement and assign this template to tree.

 private void BindTree()
 {
    tvMain.ItemTemplate = GetTemplate(); 
    tvMain.ItemsSource = WorldArea.GetAll(); 
 }

 private HierarchicalDataTemplate GetTemplate()
 {              
    //create the data template
    HierarchicalDataTemplate dataTemplate = new HierarchicalDataTemplate();

    //create stack pane;
    FrameworkElementFactory grid = new FrameworkElementFactory(typeof(Grid));
    grid.Name = "parentStackpanel";
    grid.SetValue(Grid.WidthProperty, Convert.ToDouble(100));
    grid.SetValue(Grid.HeightProperty, Convert.ToDouble(24) );
    grid.SetValue(Grid.MarginProperty, new Thickness(2));
    grid.SetValue(Grid.BackgroundProperty, new SolidColorBrush( Colors.LightSkyBlue));
              
    // Create Image 
    FrameworkElementFactory image = new FrameworkElementFactory(typeof(Image));
    image.SetValue(Image.MarginProperty, new Thickness(2));
    image.SetValue(Image.WidthProperty, Convert.ToDouble(32));
    image.SetValue(Image.HeightProperty, Convert.ToDouble(24));
    image.SetValue(Image.VerticalAlignmentProperty, VerticalAlignment.Center );
    image.SetValue(Image.HorizontalAlignmentProperty, HorizontalAlignment.Right);
    image.SetBinding(Image.SourceProperty, new Binding() 
		{ Path = new PropertyPath("ImageUrl") });
    
    grid.AppendChild(image);

    // create text
    FrameworkElementFactory label = new FrameworkElementFactory(typeof(TextBlock));
    label.SetBinding(TextBlock.TextProperty, 
		new Binding() { Path = new PropertyPath("Name") });
    label.SetValue(TextBlock.MarginProperty, new Thickness(2));
    label.SetValue(TextBlock.FontWeightProperty, FontWeights.Bold);
    label.SetValue(TextBlock.ToolTipProperty, new Binding());

    grid.AppendChild(label);

    dataTemplate.ItemsSource = new Binding("Countries"); 

    //set the visual tree of the data template
    dataTemplate.VisualTree = grid;

    return dataTemplate;
 }

Template By Data Type

A very nice flexibility provided by WPF is you can create your template by data type. Suppose you want have to show different type of objects in tree and you want to differentiate them on UI. It is not a big problem in WPF. Simply create Template by Data type and bind source with tree or manually add objects. Your tree will pick template according to data type.

Using Data Template

Simply create data template in any resource as I created in tree resource. And set its data type as I did usingDataType="{x:Type loc:WorldArea}".

 <TreeView Name="tvMain">
    <TreeView.Resources>

        <DataTemplate DataType="{x:Type loc:WorldArea}">
            <Border Width="150" BorderBrush="RoyalBlue" 
		Background="RoyalBlue"  BorderThickness="1" 
		CornerRadius="2" Margin="2" Padding="2" >
                <StackPanel Orientation="Horizontal" >
                    <TextBlock  Text="{Binding Path=Name}" 
			FontWeight="Bold" Foreground="White"></TextBlock>
                </StackPanel>
            </Border>
        </DataTemplate>

        <DataTemplate  DataType="{x:Type loc:Country}">
            <Border Width="132"  Background="LightBlue" CornerRadius="2" Margin="1" >
                <StackPanel Orientation="Horizontal" >
                    <Image Margin="2" Source="{Binding Path=ImageUrl}"></Image>
                    <TextBlock Margin="2"  Text="{Binding Path=Name}"></TextBlock>
                </StackPanel>
            </Border>
        </DataTemplate>

    </TreeView.Resources>
 </TreeView>

Using Hierarchical Template

You can also create hierarchical template by data type.

 <TreeView Name="tvMain">
    <TreeView.Resources>

        <HierarchicalDataTemplate DataType="{x:Type loc:WorldArea}" 
			ItemsSource="{Binding Path=Countries}">
            <Border Width="150" BorderBrush="RoyalBlue" Background="RoyalBlue" 
		 BorderThickness="1" CornerRadius="2" Margin="2" Padding="2" >
                <StackPanel Orientation="Horizontal" >
                    <TextBlock  Text="{Binding Path=Name}" 
			FontWeight="Bold" Foreground="White"></TextBlock>
                </StackPanel>
            </Border>
        </HierarchicalDataTemplate>
                
        <HierarchicalDataTemplate DataType="{x:Type loc:Country}">
            <Border Width="132"  Background="LightBlue" CornerRadius="2" Margin="1" >
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                        <ColumnDefinition Width="26"></ColumnDefinition>
                    </Grid.ColumnDefinitions>

                    <TextBlock Margin="2"  Text="{Binding Path=Name}"></TextBlock>

                    <Image Grid.Column="1" Margin="2" 
			Source="{Binding Path=ImageUrl}"></Image>
                </Grid>
            </Border>
        </HierarchicalDataTemplate>

    </TreeView.Resources>
 </TreeView>


This article, along with any associated source code and files, is licensed under 
The Code Project Open License (CPOL)



반응형
반응형

http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNO=20&no=8308


[C++0x] Lambda Expressions and Closures

 

작성일 : 2008.11.23       

작성자 : 아이오 교육센터

www.ioacademy.co.kr

 

글 순서

1. 기본개념

2. 람다 표현식(Lambda expressions)과 and 클로져(closure)

3. 람다 표현식과 리턴 타입

4. Capturing Local Variable

5. Nullary Lambda

6. Mutable lambda

 
1. 기본 개념

 STL의 알고리즘 중에는 함수 객체를 인자로 받는 것이 있습니다. for_each() 알고리즘이 대표적인 경우 입니다. 아래의 코드는 for_each()를 사용해서 주어진 구간의 모든 요소를 화면에 출력하는 코드 입니다.

01: #include <iostream>
02: #include <algorithm>
03: using namespace std;
04: 
05: struct ShowFunctor
06: {
07:         void operator()(int n) const
08:         {
09:                 cout << n << endl;
10:         }
11: };
12: int main()
13: {
14:         int x[10] = { 1,2,3,4,5,6,7,8,9,10};
15:         for_each( x, x+10, ShowFunctor() );
16: }

 

 

 그런데 위 코드에 있는 ShowFunctor 같은 함수를 자주 만들어야 한다면 좀 번거로운 일입니다. C++0x는 ShowFunctor 와 같은 함수객체를 보다 쉽게 만들 수 있는 “람다 표현식(Lambda express)”라는 개념을 제공합니다. 아래 코드는 위 코드와 동일한 일을 수행합니다. 단, 완전한 함수객체를 만들어 사용하지 않고 람다 표현식을 사용하고 있습니다.

 
1: int main()
2: {
3:         int x[10] = { 1,2,3,4,5,6,7,8,9,10};
4:         for_each( x, x+10, [](int n){ cout << n << endl;} );
5: }

 위 예제를 포함한 이 글에 나오는 모든 예제들은 VS2010CTP 를 사용해서 test 되었습니다.

 

 위 코드 중 다음의 표현이 람다 표현식 입니다.

      [](int n){ cout << n << endl;}

 람다 표현식을 보고 컴파일러는 함수객체 클래스를 정의하고 객체를 생성하게 됩니다. 즉, 위 코드는 아래의 코드와 유사한 의미를 가지고 있습니다.

 
01: class closure_object
02: {
03: public:
04:         void operator()(int n) const
05:         {
06:                 cout << n << endl;
07:         }
08: };
09: int main()
10: {
11:         int x[10] = { 1,2,3,4,5,6,7,8,9,10};
12:         for_each( x, x+10, closure_object() );
13: }
 

람다 표현식에 의해 컴파일러가 생성한 함수객체는 클로져 객체(Closure Object) 라고 부릅니다.클로져 객체는 함수호출연산자, 생성자, data멤버를 가진 함수객체와 유사하게 동작합니다.

 

람다 표현식을 간단히 살펴 보도록 하겠습니다..

 
 - [] 는 “lambda introducer” 라고 부르는데, 람다 표현식이 시작됨을 나타냅니다.
 - (int n) 은 “람다 파라미터 선언(lambda parameter declaration)” 이라고 부르는데, 클로져 객체의 함수호출 연산자(즉, ()연산자)가 가져야 하는 파라미터 목록을 컴파일러에게 알려주는 것입니다.
 - 마지막으로 “{ cout << n << endl;}” 는 클로져 객체의 함수 호출연산자의 구현부를 정의 하는 것입니다.
 - 디폴트로 람다 표현식의 리턴 타입은 void를 리턴 합니다.
 - 여러 개의 람다 표현식은 각각 자신만의 타입을 가지게 됩니다.
 

물론, 람다 표현식을 사용하지 않고 완전한 함수객체를 만들어 사용하면 되지만 람다 표현식을 사용하는 것이 좀더 편리 합니다.

 
2. Lambda Expression and Closure
 

[] 를 사용해서 익명의 함수객체를 명시하는 표현 식을 “람다 표현식(lambda expression)” 또는 “람다 함수(lambda function)” 라고 합니다. 또한, 람다표현식의 결과로 컴파일러에 의해 자동으로 생성된 익명의 함수객체(unnamed function object) 를 “클로져(Closure)” 라고 합니다.

 

람다 표현식의 구현은 여러 줄로 구성될 수 도 있습니다.

 
01: #include <iostream>
02: #include <algorithm>
03: using namespace std;
04: 
05: int main()
06: {
07:         int x[10] = { 1,2,3,4,5,6,7,8,9,10};
08: 
09:         for_each( x, x + 10, [](int n ) {
10:                 if ( n % 2 == 0 )
11:                         cout << "even ";
12:                 else
13:                         cout << "odd ";
14:         });
15: 
16:         cout << endl;
17: }
 

3. Lambda Expression and return type

 

람다 표현식은 리턴값은 가질수도 있습니다. 아래의 예제를 보겠습니다

 
01: #include <iostream>
02: #include <algorithm>
03: #include <vector>
04: using namespace std;
05: 
06: int main()
07: {
08:         int x[10] = { 1,2,3,4,5,6,7,8,9,10};
09:         vector<double> v;
10: 
11:         transform( x, x+10, back_inserter(v), [](int n) -> double {
12:                 if ( n % 2 == 0 ) return n;
13:                 return n / 2.0;
14:         });
15: 
16:         for_each( v.begin(), v.end(), [](double n) { cout << n << " ";});
17:         cout << endl;
18: }
 

“->double” 은 “lambda-return-type-clause” 라고 부르는데, 람다 표현식에서 리턴 타입을 지정하는 구문입니다.

 

아래와 같은 경우, 리턴 타입을 지정하는 것은 생략할 수 있습니다.

 

1. 람다 표현식이 리턴하는 값이 없을 경우 즉, “->void”는 생략이 가능합니다.

2. 람다 표현식이 한 개의 return 문장만을 가지고 있을 경우. 컴파일러는 해당 return 표현식 으로 부터 리턴 타입을 추론할 수가 있습니다.

 
01: #include <iostream>
02: #include <algorithm>
03: #include <vector>
04: using namespace std;
05: 
06: int main()
07: {
08:         int x[10] = { 1,2,3,4,5,6,7,8,9,10};
09:         vector<double> v1(10);
10:         vector<double> v2(10);
11: 
12:         // return 문장이 한 개 입니다. "?>double" 는 생략 가능 합니다.
13:         transform( x, x+10, v1.begin(), [](int n) { return n / 2.0;});
14: 
15:         // return 문이 없습 니다. “?>void” 는 생략 가능 합니다.
16:         for_each( v1.begin(), v1.end(), [](double d) { cout << d << " ";});
17:         cout << endl;
18: 
19:         // 2개 이상의 return 문이 있습니다. 반드시 "?>double" 을 표시 해야 합니다.
20:         transform( x, x+10, v1.begin(), [](int n)->double {
21:                 if ( n % 2 == 0 ) return n;
22:                 return n / 2.0;
23:         });
24: 
25:         for_each( v1.begin(), v1.end(), [](double d) { cout << d << " ";});
26:         cout << endl;
27: 
28:         // 역시 1개의 return 문 입니다.
29:         transform( x, x+10, v1.begin(), v2.begin(), [](int a, double d){ return a + d;});
30:         for_each( v2.begin(), v2.end(), [](double d) { cout << d << " ";});
31:         cout << endl;
32: }
 
 

4. Capturing Local Variable

 

  C++에서 함수 객체를 사용하는 이유 중의 하나는 상태를 가질 수 있다는 점입니다. 지금까지의 람다 표현식은 상태를 가지지 않았습니다. 하지만 지역변수를 캡쳐(capture) 하므로서 람다 표현식도 상태를 가질수가 있습니다. 아래 예제를 보겠습니다.

01: int main()
02: {
03:         int x[10] = { 1,3,5,7,9,11,13,15,17,19};
04: 
05:         int low = 12;
06:         int high = 14;
07: 
08:         int* p = find_if( x, x+10, [low, high](int n) { return low < n && n < high;});
09: 
10:         cout << *p << endl;
11: }
 

 Lambda introducer 인 “[]” 안에는 지역변수를 넣으 므로서 해당 지역변수를 람다 표현식안에서 사용할수있습니다. 이러한 것을 “capture list” 라고 합니다. “[low, high]”라고 표시하므로서 low, high 지역변수를 람다표현식 안에서 사용할 수 있습니다. “capture list”를 사용하지 않을 경우 람다 표현식 안에서 지역변수에 접근할 수는 없습니다.

 

결국 위 표현식은 아래코드와 같은 의미를 가지게 됩니다.

 
01: class closure_object
02: {
03: private:
04:         int min;
05:         int max;
06: public:
07:         closure_object( int l, int h ) : min(l), max(h) {}
08:         bool operator()(int n) const { return min < n && n < max; }
09: };
10: 
11: int main()
12: {
13:         int x[10] = { 1,3,5,7,9,11,13,15,17,19};
14:         int low = 12;
15:         int high = 14;
16: 
17:         int* p = find_if( x, x+10, closure_object(low, high) );
18:         cout << *p << endl;
19: }
 

디폴트 캡쳐인 “[=]”를 사용하면 모든 지역 변수를 람다 표현식에서 사용할 수 있습니다.

 
1: int main()
2: {
3:         int x[10] = { 1,3,5,7,9,11,13,15,17,19};
4:         int low = 12;
5:         int high = 14;
6: 
7:         int* p = find_if( x, x+10, [=](int n) { return low < n && n < high;});
8:         cout << *p << endl;
9: }
 

“[low, high”] 또는 “[=]” 는 모두 지역변수를 값으로(by value)로 캡쳐 합니다. 아래 와 같이 사용 하므로서 지역변수를 참조(by reference)로 캡쳐 할 수 있습니다. 즉, 람다 표현식 안에서 지역변수의 값을 변경 할 수 있습니다.

 
1: int main()
2: {
3:         int x[10] = { 1,2,3,4,5,6,7,8,9,10};
4:         int sum = 0;
5: 
6:         // x~x+10 에서짝수의합을구하는람다표현식입니다.
7:         for_each( x, x+10, [&sum] (int n) { if ( n % 2 == 0 ) sum += n;});
8: 
9:         cout << sum << endl;
10: }
 

 “[&sum]” 은 지역변수 sum 을 람다 표현식에서 참조로 사용하겠다는 의미 입니다. 즉, 아래의 코드와 동일한 의미를 가지게 됩니다.

 
01: class closure_object
02: {
03: private:
04:         int& ref;
05: public:
06:         closure_object ( int& r ) : ref(r) {}
07:         void operator()(int n) const { if ( n % 2 == 0 ) ref += n; }
08: };
09: 
10: int main()
11: {
12:         int x[10] = { 1,2,3,4,5,6,7,8,9,10};
13:         int sum = 0;
14: 
15:         for_each( x, x+10, closure_object( sum ) );
16:         cout << sum << endl;
17: }
 

 “[&]”를 사용 하므로서 모든 지역변수를 참조를 캡쳐 할 수도 있습니다.

또한 모든 지역변수를 값으로([=]) 디폴트 캡쳐를 사용하면서도 특정 변수만을 참조로 캡쳐 할 수도 있습니다.

 
01: int main()
02: {
03:         int x[10] = { 1,2,3,4,5,6,7,8,9,10};
04:         int low = 3;
05:         int high = 8;
06:         int sum = 0;
07: 
08:         // low ~ high 사이의 합을 구하는 람다 표현식 입니다.
09:         for_each( x, x+10, [=, &sum](int n) { if ( low < n && n <high) sum += n; });
10:         cout << sum << endl;
11: }
 

이번에는 멤버 함수 안에서 람다 표현식을 사용하는 경우를 생각해 봅시다..

 
01: class Test
02: {
03: public:
04:         void foo() const
05:         {
06:                 int x[10] = { 1,2,3,4,5,6,7,8,9,10};
07: 
08:                 // 멤버 data인 base를 캡쳐 하려고 한다. 하지만 error.
09:                 for_each( x, x+10, [base](int n) { cout << base + n << " ";});
10:                 cout << endl;
11:         }
12: 
13:         Test() : base(100) {}
14: private:
15:         int base;
16: };
17: 
18: int main()
19: {
20:         Test t;
21:         t.foo();
22: }
 

이 경우에는 아래처럼 [this], 또는 [=] 를 사용하면 멤버 data 를 캡쳐할 수 있습니다.

 
01: class Test
02: {
03: public:
04:         void foo() const
05:         {
06:                 int x[10] = { 1,2,3,4,5,6,7,8,9,10};
07: 
08:                 for_each( x, x+10, [this](int n) { cout << base + n << " ";}); // 또는 [=]
09:                 cout << endl;
10:         }
11:         Test() : base(100) {}
12: private:
13:         int base;
14: };
 
5. Nullary Lambda

 

파라미터를 갖지 않는 람다 표현식이 만들수 도 있습니다. 이 경우 파라미터 리스트의 ()를 생략할 수도 있습니다. 다음 코드를 살펴 봅시다.

 
01: int main()
02: {
03:         int x[10] = {0};
04:         int y[10] = {0};
05:         int i = 0;
06:         int j = 0;
07: 
08:         generate( x, x+10,[&i]() { return ++i;});
09:         generate( y, y+10,[&j] { return ++j;}); // () 를생략해도된다.
10: 
11:         for_each( x, x+10, [](int n) { cout << n << " ";});
12:         cout << endl;
13: 
14:         for_each( y, y+10, [](int n) { cout << n << " ";});
15:         cout << endl;
16: }

 

 

6. Mutable Lambda

 

클로져 객체의 함수 호출연산자(operator())는 상수 함수로 만들어 집니다. 따라서, 지역 변수를 캡쳐해 사용하는 람다 표현식은 자신의 상태를 변경 할 수 없습니다. 이경우 mutable 키워드를 사용 하면 값으로 캡쳐한 지역변수의 값을 변경할 수 있습니다.

 
01: int main()
02: {
03:         int x[10] = { 1,3,5,7,9,2,4,6,8,10};
04:         int i = 0;
05: 
06:         // error. 값으로캡쳐한지역변수의값을변경할수없다.
07:         for_each( x, x+10, [=](int n) { cout << ++i << " : " << n << endl;});
08: 
09:         // ok.
10:         for_each( x, x+10, [=](int n) mutable { cout << ++i << " : " << n << endl;});
11: }
 
boost에서 지원하던 람다개념을 C++0x에서는 언어 차원에서 지원하므로서 STL을 훨씬 편리 하게 사용할 수가 있게 되었습니다.
 





반응형
반응형

http://dotnetmvp.tistory.com/37

15. [WPF 기초 강좌] 사용자입력 1


안녕하세요.

WPF 기초강좌를 진행하는 김창민입니다.

 

 

이제 완전 따듯한 봄이되었내요...

아직 꽃들만 피지 않았지 바람은 따듯한 바람이 불어옵니다.

좀더 더워지기전에 스피치를 올려 강좌에 집중해야겠내요.. ㅋㅋ

 

 

그럼 오늘 강좌를 시작하겠습니다.


오늘 같이 알아볼 내용은 사용자 입력으로 사용자가 직접 키보드나 마우스스타일러스 펜 등을 이용하여 값을 추가변경하거나 이벤트를 발행 시키고자 할 때 사용하는 입력 방식을 말합니다.

그 중에서 오늘은 키보드를 이용한 입력방식에 대해 알아볼 것이며 간단한 예제로 키입력 이벤트나 클래스에서 지원하는 메서드의 사용방법에 대해 알아보겠습니다.



기본적으로 입력을 관리하는 입력API는 UIElement, ContentElement, FrameworkElement  FrameworkContentElement의 영향을 받으며 키 입력마우스 버튼클릭마우스 휠 Up-Down, 마우스 이동 등에 관한 입력 이벤트를 제공해 줍니다입력 이벤트는 라우트된 이벤트를 지원하기 때문에 버블링터널링이 모두 가능합니다예를 들어 키보드를 누르는 입력 이벤트는  KeyDown, PreviewKeyDown 이벤트가 연결되어 있습니다.

기본 입력 API 이외에도 Keyboard 클래스와 Mouse 클래스는 키보드 및 마우스 입력을 처리하기 위해 추가 API를 제공합니다.

 

 

- Keyboard 클래스

 

Keyboard 클래스는 키보드 관련 이벤트메서드키보드상태에 관한 속성을 제공해 줍니다. 

다음 표는 키보드 입력 이벤트들을 나열해 놓은 것입니다.

 

이벤트

설명

PreviewGodKeyboardFocus,

GodKeyboardFocus

컨트롤이 포커스를 받았을 때

PreviewLostKeyboardFocus,

LostKeyboardFocus

컨트롤이 포커스를 잃었을 때

GotFocus

컨트롤이 논리적 포커스를 받았을 때

LostFocus

컨트롤이 논리적 포커스를 잃었을 때

PreviewKeyDown, KeyDown

키가 눌렸을  

PreviewKeyUp, KeyUp

키가 눌렸다 떼어졌을 때

PreviewTextInput, TextInput

컨트롤이 텍스트 입력을 받았을 때



예제를 통해 간단한 키입력에 관한 이벤트와 몇가지 속성메서드에 대해 알아보고 Keyboard 클래스에서 제공하는 이벤트외에 UIElement에서 제공하는 이벤트에 대해 함께 알아보고 Keyboard 이벤트의 라우트된 이벤트가 지원이 되는를 터널링 이벤트를 통해 알아보도록 하겠습니다.

 

우선 VisualStudio 2008을 실행시켜 “UserInput”이라는 새 프로젝트를 생성합니다.






Window1.xaml Label 컨트롤 2개와 Textbox 컨트롤 1개를 Window Grid 안에 배치하겠습니다.

 

 

<!--Window1.xaml -->

<Window x:Class="UserInput.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window1" Height="300" Width="300" Keyboard.KeyDown="Window_Keyboard_KeyDown"  KeyDown="Window_KeyDown" >

    <Grid>

        <Label    Height="28" Margin="12,12,12,0" Name="label1" VerticalAlignment="Top">Label1</Label>

        <Label    Height="28" Margin="12,46,12,0" Name="label2" VerticalAlignment="Top">Label2</Label>

        <TextBox Margin="12,80,12,0" Name="textBox1" PreviewKeyUp="textBox1_PreviewKeyUp" Height="23" VerticalAlignment="Top" />

    </Grid>

</Window>

 

 

XAML 코드를 보시면 Window Keyboard 클래스에서 지원하는 “Keyboard.KeyDown” 이벤트와UIElement에서 지원하는 “KeyDown” 이벤트를 추가하였고 Label 컨트롤은 Grid안에 Margin으로 위치만 잡아주었습니다그리고 Textbox는 라우트된 이벤트의 tunneling을 테스트해 보기위해 라우트된 이벤트를 추가하였습니다.

 

다음으로 “Window1.xaml.cs”로 이동하여 이벤트핸들러에서 실행될 코드를 작성하겠습니다.

이벤트 핸들러에서 실행할 코드는 이벤트의 실행여부를 확인하기 위해 Label, Textbox 컨트롤에 텍스트로 표시해 주려합니다.

 

<!--Window1.xaml.cs -->

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

 

namespace UserInput

{

    public partial class Window1 : Window

    {

        public Window1()

        {

            InitializeComponent();

        }

 

        private void Window_Keyboard_KeyDown(object sender, KeyEventArgs e)

        {

            label1.Content = "Keyboard.KeyDown";

        }

 

        private void Window_KeyDown(object sender, KeyEventArgs e)

        {

            label2.Content = "UIElement.KeyDown";

        }

 

        private void textBox1_PreviewKeyUp(object sender, KeyEventArgs e)

        {

            textBox1.Text = "textBox1_PreviewKeyUp";

        }

    }

}

 

이제 간단한 테스트 코드 작성은 끝이 났습니다 실행을 시켜 키입력 이벤트를 확인해 보시고 Textbox에 키입력으로 라우트된 이벤트 역시 실행이 되는지도 확인해 보세요




 

 

 

실행 결과로 키보드 입력이 되면 Keyboard 클래스에서 지원하는 이벤트와 UIElement에서 지원하는 이벤트가 전부 실행되며 TextBox의 라우트된 이벤트 역시 실행되는 것을 알 수 있습니다.

 

이번에는 Keyboard 클래스에서 지원하는 “GetKeyStates”메서드를 사용해 보겠습니다.

위 프로젝트에서 Keyboard.KeyDown이벤트를 그대로 사용하기 위해 이벤트 핸들러 안에 사용했던 코드(label1.Content = "Keyboard.KeyDown";)를 주석 처리하겠습니다.

그리고 아래 코드를 입력하겠습니다.



 

if (Keyboard.GetKeyStates(Key.Enter) == KeyStates.Down)

label1.Content = "Enter 키를 누르셨습니다.";

else

label1.Content = "Enter 키를 누르세요";

 

“GetKeyStates”메서드는 지정한 키의 상태를 가져오는 메서드로 “KeyStates”  Down, None, Toggled의 값을 가져옵니다.

위 코드는 Keyboard Down 이벤트시 ‘Enter Key’의 상태를 GetKeyStates로 확인하여 엔터키가 “Down”이 되었다면 그에 해당하는 메시지를 Label에 보여주는 동작을 하게 될 것입니다.

 

그럼 실행을 시켜  결과를 보도록 하죠..

 

 

Enter Key 입력시




Enter Key 아닌 Key 입력시


 

지금까지 키보드 입력에 대해 간단히 알아보았습니다.

사용자 입력중에 키보드입력과 마우스입력은 가장 많이 사용됨으로 꼭 알아두실 필요가 있고 그리 어렵지 않으니 쉽게 익숙해지실 것입니다.

 

Keyboard 클래스에 대해서는 MSDN에서 개인적인 공부를 꼭 하시길 바랍니다.

http://msdn.microsoft.com/ko-kr/library/system.windows.input.keyboard.aspx

 

 

 

이번 시간은 사용자 입력의 첫번째 시간으로 키보드 입력에 대해 알아보았습니다.

다음 시간에는 계속해서 마우스를 이용한 이벤트즉 마우스 입력에 대해 알아보도록 하겠습니다.

수고하셨습니다.








 

 

 

Posted by 强太風
  1. ADC

    포커스나 논리적 포커스가 키보드에서 무슨 의미를 하는건가요??

    2009/08/04 16:48 ADDR : EDIT/ DEL : REPLY ]
    • 키보드입력을 이용해 키보드 클래스의 관련 이벤트를 사용하려면 우선 키보드입력을 받은 요소(Control)가 무엇인지 알려줘야겠죠?.. 포커스는 요소가 입력받을 준비?, 입력 받을 요소가 입력 받을 상태가 가능한 상태로 만들어주는 것입니다..

      2009/08/04 22:34 ADDR : EDIT/ DEL ]
  2. 이영민

    엔터키 예제에서... 엔터키를 누를때 마다 키 상태가 토글되는것 같은데, 제가 뭘 잘못 입력해서일까요?

    2010/08/13 10:57 ADDR : EDIT/ DEL : REPLY ]
    • 안녕하세요 제가 휴가를 다녀오느라 답변이 늦었내요..
      질문하신 내용은 Enter키를 누를때 마다 키 상태가 토글되는 것을 말씀하신것 같은데 이영민님이 잘못하신것은 없구요. Enter키가 토글 되는것은 테스트를 해보시면 아시겠지만 Enter키 뿐만 아니라 다른키 역시 key 상태가 Down -> Toggle -> Down -> Toggle 로 변경되게 되는 것을 아실 수 있을 겁니다. 예제에서 If 문을 다음과 같이 수정해보세요.. if (Keyboard.IsKeyDown(Key.Enter) == true) 그럼 Enter Key가 Down되었을때의 Key상태를 알 수 있을 것입니다.

      2010/08/30 13:36 ADDR : EDIT/ DEL ]
  3. 나며기

    강좌완 크게 관계가 없겠지만 Enter키 체크 부분을 아래와 같이 고쳐주시면 정확하게 체크가 가능합니다
    ^_^;
    (엔터키 누르고 다시 누르면 비정상 동작합니다 ㅎㅎ;)

    if((Keyboard.GetKeyStates(Key.Enter) & KeyStates.Down) > 0)

    강의 잘 듣고있습니다.

    마지막 강의를 향하여!!! 고고싱

    2012/08/23 14:47 ADDR : EDIT/ DEL : REPLY ]
  4. 다른 cs 파일에서 textBox1를 조작할려면 어떻게 해야 하나요?

    2013/03/25 16:19 ADDR : EDIT/ DEL : REPLY ]


반응형
반응형

http://goo.gl/FHk67U



마우스 더블클릭


void image_MouseDown(object sender, MouseButtonEventArgs e)
{
 if (e.ChangedButton == MouseButton.Left && e.ClickCount == 2)
 {
  Close();                
 }
}










http://dotnetmvp.tistory.com/38

16. [WPF 기초 강좌] 사용자입력 2



안녕하세요.

WPF 기초강좌를 진행하는 김창민입니다.

 

 

오늘 강좌를 시작하겠습니다.

 

 

 

오늘은 사용자 입력 두번째 시간으로 마우스 입력에 대해 알아보도록 하겠습니다.

 

 

 

 

키보드 입력은 어떤 요소(컨트롤)가 포커스(Focus)되어있는냐에 따라서 이벤트를 실행하는 요소가 정해지는데 마우스 입력은 어떤 요소가 마우스 화살표 또는 포인터 바로 아래에 위치하고 있느냐에 따라 마우스 이벤트를 실행하게될 요소가 달라집니다마우스 포인터 바로 아래있는 요소가 이벤트를 받게 될 대상이 되는 것입니다.

 

마우스 입력 역시 UIElement 클래스로부터 파생되어지며 이벤트와 속성등이 제공되어집니다.

 

 

- Mouse 클래스

 

다음 표는 마우스 입력 이벤트들을 나열해 놓은 것입니다.

 

이벤트

설명

GotMouseCapture

컨트롤에 마우스 캡처 중임

LostMouseCapture

컨트롤에서 마우스 캡처를 잃음

MouseEnter

마우스 포인터가 컨트롤의 영역으로 들어왔음

MouseLeave

마우스 포인터가 컨트롤의 영역 밖으로 나감

PreviewMouseLeftButtonDown,

MouseLeftButtonDown

마우스 포인터가 컨트롤의 영역안에 있을 때 마우스 왼쪽 버튼이 눌렸을 때

PreviewMouseLeftButtonUp,

MouseLeftButtonUp

마우스 포인터가 컨트롤의 영역안에 있을 때 마우스 왼쪽 버튼이 눌렸다 떼어졌을 때

PreviewMouseRightButtonDown,

MouseRightButtonDown

마우스 포인터가 컨트롤의 영역안에 있을 때 마우스 오른쪽 버튼이 눌렸을 때

PreviewMouseRightButtonUp,

MouseRighttButtonUp

마우스 포인터가 컨트롤의 영역안에 있을 때 마우스 오른쪽 버튼이 눌렸다 떼어졌을 때

PreviewMouseDown,

MouseDown

마우스 포인터가 컨트롤의 영역안에 있을 때 마우스 버튼이 눌렸을 때

PreviewMouseUp,

MouseUp

마우스 포인터가 컨트롤의 영역안에 있을 때 마우스 버튼이 눌렸다 떼어졌을 때

PreviewMouseMove,

MouseMove

마우스 포인터가 컨트롤 영역내어서 움직였을 때

PreviewmouseWheel,

MouseWheel

마우스 포인터가 컨트롤 영역내에 있으면서 마우스 휠이 움직였을 때

QueryCursor

마우스 포인터가 컨트롤 영역내에 있는 동안 마우스 포인터의 모양이 결정되었을 때

 

 

위 이벤트들은 아마 특별히 설명을 하지 않아도 많이 사용하고 많이 보아왔기 때문에 어떤 이벤트들인지 휜히 다 아시리라 생각합니다.

위 표에있는 이벤트들 말고도 Mouse클래스에는 몇가지 속성들과 메서드를을 제공해 줍니다.

 

다음 예제를 통해서 몇가지 이벤트메서드속성에 대해 설명을 진행하겠습니다.

 

우선 VisualStudio 2008을 실행시켜 “MouseInput”이라는 새 프로젝트를 생성합니다.

그리고 프로젝트에 생성된 “Window1”을 “MouseEvent”로 변경하겠습니다.

 

 

이번 예제에서는 Mouse의 이벤트 중 MouseDown, MouseMove, MouseUp, MouseRightButtonDown 이벤트를 등록해 사용하고 Mouse Capture, GetPosition 메서드에 대해 알아보도록 하겠습니다.

 

 

 

다음으로 MouseEvent.xaml Ellipse 컨트롤과 Button 컨트롤, Label 컨트롤을 Window Grid 안에 배치하겠습니다.

 

 

<!-- MouseEvent.xaml -->

<Window x:Class="MouseInput.MouseEvent"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window1" Height="300" Width="300">

    <Grid>

        <Ellipse Margin="70,47,72,79" Name="ellipse1" Stroke="Black" Fill="Red" />

        <Label Height="28" Margin="0,0,0,12" Name="label1" VerticalAlignment="Bottom" HorizontalContentAlignment="Center" >Label</Label>

<Button Name="button1" Height="23" HorizontalAlignment="Right" VerticalAlignment="Top" Width="75">Button</Button>

    </Grid>

</Window>

 

 

다음은 “MouseEvent.xaml.cs”로 이동하여 이벤트를 등록하고 핸들러부분에 실행될 코드를 작성하겠습니다.

 

 

<!-- MouseEvent.xaml.cs -->

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

 

namespace MouseInput

{

    public partial class MouseEvent : Window

    {

        public MouseEvent()

        {

            InitializeComponent();   

            ellipse1.MouseDown += new MouseButtonEventHandler(ellipse1_MouseDown);

            ellipse1.MouseMove += new MouseEventHandler(ellipse1_MouseMove);

            ellipse1.MouseUp += new MouseButtonEventHandler(ellipse1_MouseUp);

            this.MouseRightButtonDown += new MouseButtonEventHandler(Window1_MouseRightButtonDown);

        }

 

        void ellipse1_MouseDown(object sender, MouseButtonEventArgs e)

        {

            label1.Content = "MouseDown";

            Mouse.Capture(ellipse1);

        }

 

        void ellipse1_MouseMove(object sender, MouseEventArgs e)

        {

            label1.Content = "MouseMove" + Mouse.GetPosition(ellipse1);

        }

 

        void ellipse1_MouseUp(object sender, MouseButtonEventArgs e)

        {

            label1.Content = "MouseUp" + Mouse.GetPosition(ellipse1);

        }

 

        void Window1_MouseRightButtonDown(object sender, MouseButtonEventArgs e)

        {

            Mouse.Capture(null);

        }

 

        private void button1_Click(object sender, RoutedEventArgs e)

        {

            if (ellipse1.Fill == Brushes.Red)

                ellipse1.Fill = Brushes.Blue;

            else

                ellipse1.Fill = Brushes.Red;

        }

    }

}

 

 

 

위 코드에서 Window생성자 부분에 이벤트를 등록하는 코드가 있지요?..


ellipse1.MouseDown += new MouseButtonEventHandler(ellipse1_MouseDown);


 

 

전에 강좌를 통해 이벤트를 코드에서 자동등록하는 방법을 설명드렸는데 혹시 모르시거나 잊어버리신 분들이 있으까봐 다시 간단히 설명해 드리겠습니다. 

 

코드에서 이벤트를 등록하려할 때 이벤트를 발생시킬 요소의 아이디를 치시고 ‘.’을 치면 IntelleSence기능이 작동하여 코드를 쉽게 입력할 수 있을 것입니다.




 

IntelleSence 창에서 원하는 코드를 찾는데 저는 ellipse1 MouseDown이벤트를 만들어주기 위해 MouseDown 이벤트를 찾아 선택을 해주겠습니다.





 

다음으로 “ellipse1.MouseDown” 이 코드 뒤에 이벤트 핸들러를 연결해 주기위해 +=” 를 입력하면 다음과 같은 설명이 나오게 될 것입니다.

 





우리는 생각 할 것 없이 시키는데로 “Tab”키를 눌러주면 됩니다.

그러면 코드가 자동으로 생성이되며 이벤트 핸들러 메서드를 작성할 것이라는 안내문이 나옵니다.

 

 

 

 

그럼 또 우린 생각할 것 없이  “Tab”키를 한번 더 눌러줍니다.

ㅋㅋ 너무나도 친절하게 다음과 같은 이벤트 핸들러 역시 자동으로 생성되어지는 것을 보실 수 있을 것입니다.




이 처럼 VisualStudio에서는 자동으로 이벤트를 쉽게 등록할 수 있는 기능을 제공해 줌으로 써 개발자가 좀 더 쉽고 간단하게 이벤트를 만들어 사용할 수 있도록 도와 주고 있습니다.

 

 

그럼 다시 본론으로 들어가서 위에 작성한 코드를 잠깐 같이 보고 실행 결과를 보도록 하겠습니다.


코드를 보시면 “ellipse1.MouseDown” 이벤트 핸들러를 보시면 Mouse.Capture(ellipse1);” 이라는 코드가 있습니다마우스의 캡처는 요소(컨트롤)가 모든 마우스의 입력 명령을 받는 시점을 나타내는데 이말은 요소를 캡처하면 마우스 포인터가 요소의 영역안에 있던지 관계없이 마우스의 입력을 받게됩니다. 그러면서 다른 요소즉 최상위 요소인 Window까지 Lock이 걸린 것 같은 현상을 보실 수 있습니다.

다음으로 MouseMove, MouseUp 이벤트 핸들러의 코드를 보시면 Mouse.GetPosition(ellipse1)”라는 메서드를 이용하여 마우스 포인터가 있는 위치 좌표를 Label에 표시해 주게 되어있습니다그런데 메서드의 인자로 “ellipse1”이란 요소를 넘겨주게 되어있는데 이는 “GetPosition”메서드에서 마우스 포인터를 좌표상으로 나타내는데 그 기준을 위에 인자로 넘긴 요소를 기준으로 좌표를 나타내게 된다는 것을 의미하게 됩니다.

그리고 Window의 “MouseRightButtonDown” 이벤트 핸들러에서는 “ellipse”에서 설정한 캡처를 해제함을 나타낸는 코드로 되어있습니다.

Button컨트롤의 역할은 마우스 캡처가 되었을 때 버튼 이벤트가 실행되는 지를 보기 위함으로 버튼이 눌려지게 된다면 ellipse의 배경색을 바꾸어주는 역할을 하게 됩니다.

 

그럼 빌드하여 실행을 시켜 보겠습니다.

(혹시 제 강좌를 보시던 분들 중에 App.xaml파일의 StartupUri를 변경하지 않고 실행이 안되신다고 하시는 분들은 이제 없으시겠죠?~ ㅋㅋ)





위와 같은 실행 창이 나오면 우선 버튼(ID:button1)이 정상적으로 동작을 하는지 버튼을 클릭해 보겠습니다.

 






원의 배경색이 파란색빨간색으로 변하는 것으로 보아 버튼 클릭 이벤트는 정삭적으로 동작하는 것을 알 수 있습니다.

 

그럼 이제 Mouse.Capture를 하기위해 빨간색 원(ID:ellipse1)을 마우스로 포인터를 가져가 보겠습니다.







마우스 포인터는 원안으로 가져가자 밑에 있는 Label에 “MouseMove”라는 글과 함께 좌표가 표시됨을 알 수 있습니다그런데 원 밖으로 마우스 포인터를 가져가면 원 밖에서는 마우스가 움직이는 동안 MouseMove이벤트는 동작하지 않는 것알 수 있습니다현재는 “MouseMove” 이벤트는 요소 영역안에 있을 때만 동작하게 됩니다.

다시 마우스 포인터는 원안으로 가져가서 원을 클릭해 보겠습니다.








원안에서 마우스를 클릭하자 Label에 “MouseUp”이란 글자와 좌표가 표시됩니다.

MouseUp은 원 안에서 마우스가 “Down”되었다가 바로 “Up”이 되자 “MouseUp”이벤트가 실행된 결과입니다.

우리는 “MouseDown” 이벤트에서 “ellipes1” 요소를 캡처하는 동작을 지정하였습니다.

당연히 마우스가 클릭되는 동작에서 MouseDown 이벤트도 실행이 되었겠지요?~


마우스캡처의 동작을 보기위해 버튼에 마우스 포인터를 이동해 보겠습니다.






그런데 한가지

 

위에 결과에서 뭔가 이상한 것이 있지 않은 가요?...

그건 바로 전에 원 밖에서 마우스 포인터이 이동했을 경우에는 MouseMove이벤트가 실행이 되지 않았는데 지금은 원 밖에서 마우스 포인터를 이동시켜도 MouseMove이벤트가 실행이 되어 Label의 좌표가 계속 변경됨을 알 수 있습니다.

처음에 마우스 캡처를 설명한 부분을 잘 기억하고 있으시다면 눈치 채셨을 것입니다.

마우스의 캡처는 요소(컨트롤)가 모든 마우스의 입력 명령을 받는 시점을 나타내는데 이말은 요소를 캡처하면 마우스 포인터가 요소의 영역안에 있던지 관계없이 마우스의 입력을 받게됨니다.” 라고 위부분에 설명을 해 놓았습니다이것으로만 봐도 현재 마우스 요소가 캡처되있는 상태임을 알 수 있습니다.

그럼 계속해서 버튼을 클릭해 보겠습니다.






버튼이 클릭이 되십니까?... 

버튼을 클릭하면서 밑에 Label을 보세요. Label에 “MouseDown”, “MouseUp”이란 글자가 변경되는 것으로보아 마우스는 클릭이 되어지는 것을 알 수 있습니다.

하지만 버튼은 클릭 되어지지 않게 됩니다.

이것은 지금 “ellipse1” 요소가 캡처되어 있는 상태이기 때문에 모든 마우스 이벤트는 “ellipse1”이 다 받게 되어있기 때문입니다.

 

간단한 예제를 통해서 “Mouse.Capture”를 알아보았는데 쉽게 이해가 되셨는지 모르겠습니다.

아직 실행하지 않은 이벤트가 하나 있는데 “MouseRightButtonDown”이벤트 입니다.

결과 창에서 마우스 오른쪽을 클릭해서 마우스 캡처를 해제한 다음에 원 밖에서의 “MouseMove”, 버튼의 클릭이 정상적으로 되는지 확인해 보세요

 

 

 

 

이번 예제는 IsMouseOver 속성과 IsMouseDirectlyOver속성에 대해 알아보고 마우스 휠 이벤트에 대한 예제를 만들어보겠습니다.

 

예제를 만들기전에 간단히 설명을 진행하고 예제의 결과를 보고 이해하는 순서로 진행을 이어가겠습니다.

IsMouseOver 속성과 IsMouseDirectlyOver은 공통점이 있습니다그것은 마우스 포인터가 현재 요소 영역안에 위치하고 있는지의 여부를 Boolean 값으로 반환해줍니다.

다시말해 요소영역안에 마우스 포인터가 위치한다면 true, 그렇지 않으면 false를 반환해 준다는 것입니다.

그러나 이둘은 약간의 차이점이 있습니다. IsMouseOver 속성은 요소의 영역안에 마우스 포인터가 위치하면 true를 반환합니다요소안에 자식 요소가 있어서 마우스 포인터가 자식요소 영역안에 있다 하더라도 true를 반환한다는 것입니다.

하지만 IsMouseDirectlyOver속성은 다릅니다이 속성은 요소의 자식요소 영역안에 마우스 포인터가 위치한다면 false를 반환하게 됩니다다시말해 현재 마우스 포인터가 자식요소가 아닌 자기자신 요소 위에 있어야만 true를 반환하게 됩니다.

 

그리고 휠 이벤트는 마우스 휠이 움직일 때 발생하는 이벤트인데 MouseWheel 이벤트 핸들러의 MouseWheelEventArgs에서 “Delta” 값을 보고 휠이 위로 움직였는지 아래로 움직였는지를 알 수 있습니다.

 

그럼 다음 예제를 작성하고 실행해 결과를 보세요..

 

 

기존 프로젝트에 “MouseEvent1”이라는 이름으로 새 창을 추가하겠습니다.









그런 다음 “MouseEvent1.xaml”페이지에 디자인을 하겠습니다.

 

 

<!—MouseEvent1.xaml -->

<Window x:Class="MouseInput.MouseEvent1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="MouseEvent1" Height="300" Width="300" MouseWheel="Window_MouseWheel">

    <Grid>

        <Button x:Name="button1" Margin="24,37,0,129" HorizontalAlignment="Left" Width="107" MouseEnter="button1_MouseEnter" MouseLeave="button1_MouseLeave" >

            <Ellipse x:Name="ellipse1" Height="40" Width="40" Fill="Red" MouseEnter="Ellipse_MouseEnter" MouseLeave="ellipse1_MouseLeave" />

        </Button>

        <Button x:Name="button2" Margin="0,37,25,129" HorizontalAlignment="Right" Width="107" MouseEnter="button2_MouseEnter" MouseLeave="button2_MouseLeave" >

            <Rectangle x:Name="Rectangle1" Height="40" Width="40" Fill="Blue" MouseEnter="Rectangle_MouseEnter" MouseLeave="Rectangle1_MouseLeave" />

        </Button>

        <Label Margin="0,0,0,69" Name="label1" FontSize="16" HorizontalContentAlignment="Center" Height="42" VerticalAlignment="Bottom">Label</Label>

        <Label FontSize="18" Height="42" HorizontalContentAlignment="Center" Name="label2" VerticalAlignment="Bottom">0</Label>

    </Grid>

</Window>

 

 

 

그리고 “MouseEvent1.xaml.cs” 페이지에 다음 코드를 작성합니다.

 

 

<!-- MouseEvent.xaml.cs -->

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

 

namespace MouseInput

{

    public partial class MouseEvent1 : Window

    {

        public MouseEvent1()

        {

            InitializeComponent();           

        }

 

        private void button1_MouseEnter(object sender, MouseEventArgs e)

        {

            label1.Content = "button1 MouseOver : " + button1.IsMouseOver.ToString();

        }

 

        private void Ellipse_MouseEnter(object sender, MouseEventArgs e)

        {

            label1.Content = "Ellipse MouseOver : " + ellipse1.IsMouseOver.ToString();

        }

 

        private void button2_MouseEnter(object sender, MouseEventArgs e)

        {

            label1.Content = "button2 MouseDirectlyOver : " + button2.IsMouseDirectlyOver.ToString();

        }

 

        private void Rectangle_MouseEnter(object sender, MouseEventArgs e)

        {

            label1.Content = "Rectangle1 MouseDirectlyOver : " + Rectangle1.IsMouseDirectlyOver.ToString();

        }

 

        private void button1_MouseLeave(object sender, MouseEventArgs e)

        {

            label1.Content = "";

        }

 

        private void button2_MouseLeave(object sender, MouseEventArgs e)

        {

            label1.Content = "";

        }

 

        private void ellipse1_MouseLeave(object sender, MouseEventArgs e)

        {

            label1.Content = "button1 MouseOver : " + button1.IsMouseOver.ToString();

        }

 

        private void Rectangle1_MouseLeave(object sender, MouseEventArgs e)

        {

            label1.Content = "button2 MouseDirectlyOver : " + button2.IsMouseDirectlyOver.ToString();

        }

 

        private void Window_MouseWheel(object sender, MouseWheelEventArgs e)

        {

            if (e.Delta == 120)

            {

                label2.Content = Convert.ToInt32(label2.Content) + 1;

            }

            else if (e.Delta == -120)

            {

                label2.Content = Convert.ToInt32(label2.Content) - 1;

            }

        }

 

    }

}

 

 

 

간단히 코드 설명을 드리자면 디자인에는 두개의 Button과 두개의 Label이 배치되어 있습니다.

그리고 두개의 버튼에는 각각 Rectangle Ellipse가 자식요소로 포함이 되어있습니다.

버튼들과 그 자식요소에는 “MouseEnter” 이벤트 들이 선언되어있어 마우스 포인터가 요소위에 올라가면 이벤트를 실행 시킬 것이고 그 이벤트안에는 IsMouseOver 속성과 IsMouseDirectlyOver속성의 반환 값을 label1에 보여주게 되있습니다.

그리고 마우스 휠 움직일 때는 lable2 1씩 증가, 1씩 감소하는 코드를 작성해 두었습니다.

그럼 App.xaml 파일을 수정하시여 결과를 보도록 하겠습니다..

 



IsMouseOver 속성




IsMouseDirectlyOver속성




MouseWhee 이벤트





이제 이해가 되시죠?...

 

정말 긴 강좌였습니다.

그리 어렵지않은 내용이였지만 나름 할 말이 많았었내요...

 

Mouse 클래스 역시 여럽지 않은 개념임으로 MSDN에서 꼭 한번 읽고 넘어 가시길 바랍니다.

http://msdn.microsoft.com/ko-kr/library/system.windows.input.mouse_members.aspx 

 

 

 

 

이번 시간까지 사용자 입력의 키보드 입력과 마우스 입력에 대해 알아보았습니다.

그리고 사용자 입력중에 하나인 스타일러스 펜 입력이 있는데 이 내용은 Tablet PC나 Digitizing PC 에서 테스트 가능한 기능임으로 현재 강좌에서는 진행을 하지 않으려 합니다.

 

다음 시간에는 처음 강좌를 시작할 때 WPF시작하기라는 주제로 잠깐 훌터보고 넘어갔단 컨트롤들에 대해 좀 더 구체적으로 알아보는 시간을 갖도록 하겠습니다.

그리고 앞으로 진행될 강좌는 가능하면 Expression Blend를 사용하여 컨트롤의 모양을 변경한다던지 개발자로서 간단히 할 수 있는 디자인 예제를 함께 만들어보는 시간도 많이 갖도록 하겠습니다.

   

긴 강좌 함께 하시느라 수고하셨습니다











Posted by 强太風
  1. 박성욱

    좋은 강좌 감사합니다. 
    그런데 이번 isMouseDirectlyOver 예제는 조금 동작이 다른 것 같아요.
    button1 위에 올라섰을때 동작은 맞고 , button1의 자식요소인 ellips1에 마우스가 올라가면,
    라벨에는 "Ellipse MouseOver : true"가 표시됩니다. 
    또한 button2 위에 올라섰을 때는 "button2 MouseDirectlyOver : false"가 표시되고 그 자식요소 rectangle1에 마우스가 올라가면, "Rectangle1 MouseDirectlyOver : true"가 표시됩니다. 
    cs소스의 이벤트처리 안의 내용을 조금 바꿔서 자식요소의 이벤트에서도 button의 isMouseDirectlyOver 를 참조 해 보아도 false이고요.
    기본적으로 button2에 마우스가 올라가서 자식요소 안까지 가지 않아도 false가 나오는 것이 이상합니다.
    자식요소 위에서 마우스를 다운한 상태를 유지 해 주면 true가 나오네요.


반응형
반응형

http://hewoo.tistory.com/5




3. CompositionTarget의 Redering 이벤트 핸들러 이용

마지막으로 CompositionTarget의 Rendering 이벤트 핸들러는 이용하는 방법이 있다. 
이것은 모니터의 수직 주파수 보다 빠른 랜더링을 요구 할때 DispatcherTimer를 포기 하고 쓰는 방법이다. 
이것도 예제 코드를 보면서 이야기 하겠다. 

 public Window1()

        {

            InitializeComponent();

            InitUI();

            SetCompositionTarget();

        }

 

 

        private void SetCompositionTarget()

        {

            CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);

        }

 

        void CompositionTarget_Rendering(object sender, EventArgs e)

        {

            Canvas.SetLeft(MyEllipseCanvas, XPos);

 

            if (XPos > this.Width)

                XPos = 0;

            else

                XPos += 0.5;

        }


엄청 간단하다.^^

CompositonTarget은 System.Windows.Media 네임 스페이스를 쓰면 이용가능하다.
한가지 특이한 사실은 DispatcherTimer를 쓸때는 Thread.Sleep(1); 해줘야 CPU 점유율이 떨어지는데, 
이건 Sleep를 쓰지 않아도 CPU 점유율이 높이않다. (오히려 DispatcherTimer 쓸때 보다 낮다.)

그렇다면  CompositonTarget은 어디서 온걸까?
바로 WPF가 화면에 객체를 뿌리는 Reder 방식인 것이다. 
WPF를 내부적으로 보면 화면에 GPU 가속을 이용하여 Thread 형식으로 오브젝트를 계속 뿌린다. 
GDI 방식과 차이가 있다. 그렇기 때문에 화면에 뿌려지는 속도가 매우 빠르다는 것을 알 수 있다.


이제 까지 3가지 애니메이션 시키는 방법에 대해 알아 보았다.
사용은 여러분 자유다.^^


추신 : 전체 소스코드를 같이 올린다. 참고하시길~!

반응형
반응형


출처 : http://scor7910.tistory.com/55



Visual C++ 팀블로그에 C++0x에 대한 소개 자료중 람다(Lambda)에 관한 내용을 번역했습니다. 
차후에 나머지도 번역해서 올리겠습니다. 
번역이 만만치 않은 작업이근영....

 원본 : 

http://blogs.msdn.com/vcblog/archive/2008/10/28/lambdas-auto-and-static-assert-c-0x-features-in-vc10-part-1.aspx

 

Lambdas, auto, and static_assert: C++0x Features in VC10, Part 1

마이크로소프트 비절 스투디오 2010CTP(Community Technology Preview)에서는 C++ 0x 포함된 lambdasautostatic_assertrvalue references  라는 4가지의 개념을 제공합니다.  여기서는 처음 세가지에 대해이야기를 하겠습니다.

첫번째로 내용을 쓰기전..:

 

1.  포스트는 Visual C++ 라이브러리 개발자인Stephan T. Lavavej 님이작성했습니다그리고 Stephan T. Lavavej님이 위의 네가지 기능에 대한 구현을 담당하지 않았음을 밝힘니다.

 

2. 내용에서 VS 2010에서 Visual C++ 컴파일러를 VC10이라고 칭할  입니다(10 2010 약어가 아님).

 

3. C++0x 아직 논의 중인 차세대 C++ 표준을 의미합니다.

(표준 위원회(The Standardization Committee) 2009 C++09라는 이름으로 발표되기 원하지만 2010이나  걸릴수 있기 때문에 x 붙였다는 조크도있다네요. C++98  C++03  현재 C++ 표준을 의미 합니다.(여기서 역사이야기는 하지 않고 2003년에 발표된 C++표준은 1998년에 발표된 C++대한 단순한 서비스팩” 이었고 대부분의 사람들은 이들의 차이점에 대해 무시하였죠.  C++03  C++0x  완전히 다릅니다.

 

4.  나는 C++ 0x 완벽하고 멋지게 구성하고 있을 표준 위원회(The Standardization Committee) 감사를 표합니다그들은 또한 아래의 링크에 좋은 자료를 올려 두었습니다 

C++0x language feature status: http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2705.html

C++0x library feature status: http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2706.html

C++0x Working Draft: http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2798.pdf

 

5.  어디에나 버그는 있습니다. (많지 않기를 원하지만..), 그게  CTP 특성입니다버그가 발견되면 마이크로 소프트 커넥트 리포팅 해주세요.

 

이제 본론으로 들어가겠습니다.

 

 

 

 

 

lambdas

C++0x에는 명명되지않은(unnamed) 함수객체(function objects) 수동으로 선언과 정의를 하지않고이것을 포함하고 있는  함수객체(function objects) 사용할  있는 람다(lambda) 수식 있습니다.

아래는 람다를 사용한 "Hello, World" 예제 입니다. :

 

C:\Temp>type meow.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

int main() {

    vector<int> v;

 

    for (int i = 0; i < 10; ++i) {

        v.push_back(i);

    }

 

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

    cout << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 meow.cpp > NUL && meow

0 1 2 3 4 5 6 7 8 9

 

 

 

 []  람다-소개자 (lambda-introducer) 입니다컴파일러에게 람다 수식이시작했다는 것을 알려주는 역할을 합니다(int n) 람다-매개변수-선언(lambda-parameter-declaration) 입니다어떤 명명되지 않은(unnamed)함수 객체 클래스의 연산자( ()연산자를 의미하는듯) 실행이 되어지는지컴파일러에게 알려주는 역할을 합니다마지막으로  { cout << n << " "; }   복합-서술(compound-statement)부분이고 , 명명되지 않은 함수 객체의 몸체(정의부입니다기본적으로 명명되지 않은 함수 객체의 연산자는 void 리턴합니다.

 

 

그러면 C++0x에서 쓰여진 람다를 현재 C++ 구현한다면 어떻게 구현되는지보겠습니다.

 

C:\Temp>type meow98.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

struct LambdaFunctor {

    void operator()(int n) const {

        cout << n << " ";

    }

};

 

int main() {

    vector<int> v;

 

    for (int i = 0; i < 10; ++i) {

        v.push_back(i);

    }

 

    for_each(v.begin(), v.end(), LambdaFunctor());

    cout << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 meow98.cpp > NUL && meow98

0 1 2 3 4 5 6 7 8 9

 

 

 

이제부터 명명되지않은 함수 객체 클래스의 () 연산자는 void 리턴한다” 람다는 void 리턴한다라고 말하겠습니다.  하지만람다 수식이 클래스를정의하고 생성하는 것은 중요하니 기억해 두세요.

 

물론람다의 복합-서술(compound-statement)구문은  여러줄로   있습니다.

 

C:\Temp>type multimeow.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

int main() {

    vector<int> v;

 

    for (int i = 0; i < 10; ++i) {

        v.push_back(i);

    }

 

    for_each(v.begin(), v.end(), [](int n) {

        cout << n;

 

        if (n % 2 == 0) {

            cout << " even ";

        } else {

            cout << " odd ";

        }

    });

 

    cout << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 multimeow.cpp > NUL && multimeow

0 even 1 odd 2 even 3 odd 4 even 5 odd 6 even 7 odd 8 even 9 odd

 

 

 

그리고람다는 항상 void 리턴 하지 않습니다만약 람다의 복합-서술(compound-statement) { return expression; } 되어 있다면람다의리턴 타입은 자동으로 수식의 타입으로 만들어 줍니다.

C:\Temp>type cubicmeow.cpp

#include <algorithm>

#include <deque>

#include <iostream>

#include <iterator>

#include <ostream>

#include <vector>

using namespace std;

 

int main() {

    vector<int> v;

 

    for (int i = 0; i < 10; ++i) {

        v.push_back(i);

    }

 

    deque<int> d;

 

    transform(v.begin(), v.end(), front_inserter(d), [](int n) { return n * n * n; });

 

    for_each(d.begin(), d.end(), [](int n) { cout << n << " "; });

    cout << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 cubicmeow.cpp > NUL && cubicmeow

729 512 343 216 125 64 27 8 1 0

 

 

 

여기서 n * n * n  int 타입이고 람다의 함수기 호출하 ()연산자는 int리턴합니다.

 

람다로  복작한 복합-서술(compound-statements)구문은  자동으로 리턴타입을 만들어   없습니다.  아래 코드와 같이 리턴타입을 명시해 주어야 합니다


C:\Temp>type returnmeow.cpp

#include <algorithm>

#include <deque>

#include <iostream>

#include <iterator>

#include <ostream>

#include <vector>

using namespace std;

 

int main() {

    vector<int> v;

 

    for (int i = 0; i < 10; ++i) {

        v.push_back(i);

    }

 

    deque<double> d;

 

    transform(v.begin(), v.end(), front_inserter(d), [](intn) -> double {

        if (n % 2 == 0) {

            return n * n * n;

        } else {

            return n / 2.0;

        }

    });

 

    for_each(d.begin(), d.end(), [](double x) { cout << x << " "; });

    cout << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 returnmeow.cpp > NUL && returnmeow

4.5 512 3.5 216 2.5 64 1.5 8 0.5 0

 

 







































“-> double”  부가적으로 사용할  있는 람다-리턴-타입-구문(lambda-return-type-clause )입니다.  많은 개발자들이  리턴 타입이 왼쪽에 오지 않는 건지 궁금해 하겠지만,  lambda-introducer ( [] ) 앞에 있지않으면 컴파일러는 람다 문법의 시작을 알수 없기 때문입니다.

 

만약 람다 리턴 타입 구문을 쓰지 않으면 다음과 같은 컴파일 에러가 발생됩니다

C:\Temp>cl /EHsc /nologo /W4 borkedreturnmeow.cpp

borkedreturnmeow.cpp

borkedreturnmeow.cpp(20) : error C3499: a lambda that has been specified to have a void return type cannot return a value

borkedreturnmeow.cpp(22) : error C3499: a lambda that has been specified to have a void return type cannot return a value

 

 

지금까지 보여준 람다는 데이터 멤버가 없는(stateless) 것들입니다.

여러분들은 지역변수를 캡쳐링(capturing)”해서 데이터 멤버를 가지고 있는람다를 만들  있습니다.   비어있는 람다 소개자lambda-introducer) [] 데이터 멤버가 없는 람다 라는 것을 의미 하고캡쳐리스트(capture-list)지정하여 데이터 멤버를 가지는 람다를 만들  있습니다.

 

C:\Temp>type capturekittybyvalue.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

int main() {

    vector<int> v;

 

    for (int i = 0; i < 10; ++i) {

        v.push_back(i);

    }

 

    int x = 0;

    int y = 0;

 

    // op>>() 입력 스트림에 개행 문자를  남겨야 하는데,

    // 이건  귀찮으므로 쓰지 않을 것을 추천합니다.

    // 대신  라인을 읽거나 읽어서 파싱하는 루틴을 만들고

    // 싶다면getline(cin,str)함수를 사용하세요.

    // 여기서는 간단하게 쓰기 위해 op>>() 썼습니다.

 

 

    cout << "Input: ";

    cin >> x >> y;

 

    v.erase(remove_if(v.begin(), v.end(), [x, y](int n) {return x < n && n < y; }), v.end());

 

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

    cout << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 capturekittybyvalue.cpp > NUL && capturekittybyvalue

Input: 4 7

0 1 2 3 4 7 8 9

 

 

캡쳐 리스트를 정의하지 않으면 아래의 오류 코드가 발생됩니다

C:\Temp>cl /EHsc /nologo /W4 borkedcapturekittybyvalue.cpp

borkedcapturekittybyvalue.cpp

borkedcapturekittybyvalue.cpp(27) : error C3493: 'x' cannot be implicitly captured as no default capture mode has been specified

borkedcapturekittybyvalue.cpp(27) : error C3493: 'y' cannot be implicitly captured as no default capture mode has been specified

 

 

(기본(default) 캡쳐에 대한 설명은 나중에…)

 

람다 수식은 기본적으로 명명되지 않은 함수 객체 클래스를 정의 한다는 것을기억해두시길 바랍니다.  복합-서술(compound-statement) 구문인 { return x < n && n < y; } 클래스의 ()연산자 함수 몸체에 해당됩니다.

어휘상 복합-서술(compound-statement) 구문이 어휘상 main() 함수 내부에있지만 개념상 main()함수 외부에 존재 하는  입니다.  그래서 main() 함수내부에 있는 지역변수를 바로 사용할  없고 람다 내부에서 캡쳐하여 사용해야합니다.

 

아래 예제는 위의람다 캡쳐 예제를 현재 C++ 표준으로 구현한  입니다.

 

C:\Temp>type capturekittybyvalue98.cpp

#include <algorithm>

#include <iostream>

#include <iterator>

#include <ostream>

#include <vector>

using namespace std;

 

class LambdaFunctor {

public:

    LambdaFunctor(int a, int b) : m_a(a), m_b(b) { }

 

    bool operator()(int n) const { return m_a < n && n < m_b; }

 

private:

    int m_a;

    int m_b;

};

 

int main() {

    vector<int> v;

 

    for (int i = 0; i < 10; ++i) {

        v.push_back(i);

    }

 

    int x = 0;

    int y = 0;

 

    cout << "Input: ";

    cin >> x >> y; // EVIL! <<- 이러면 안된다는 말입니다..

 

    v.erase(remove_if(v.begin(), v.end(), LambdaFunctor(x, y)), v.end());

 

    copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));

    cout << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 capturekittybyvalue98.cpp > NUL && capturekittybyvalue98

Input: 4 7

0 1 2 3 4 7 8 9

 

 

 

여기서,  캡쳐의 의미가 값에 의한(전달)” 이라는 것이 명확하게   있습니다지역변수의 복사본이 함수객체 내부 함수에 저장 되는 것을   있습니다.

이는 함수 객체가 캡쳐하기 위해 생성된 지역변수 보다  오래 남을  있게 합니다.

아래 사항들을 알아 두세요.

(a) 함수호출 연산자( ()연산자 ) 기본적으로 const 이기 때문에캡쳐된 복사본은 람다 내부에서 수정될  없습니다.

(b) 어떤 객체는 복사하기 비용이 많이 듭니다.  

(c) 지역변수를 변경하면 캡쳐된 복사본에는 아무런 영향을 없습니다. (값에의한 전달에 관한 내용).

 

 부분은 다음에 필요할  이야기 하겠습니다 

 

캡쳐하고 싶은 지역변수들을 모두 지정하는  대신 값에 의한 복사로  모두 캡쳐”   있습니다.  이것을 가능하게 하는 문법이 람다 소개자(lambda-introducer)  “ [=] “ 입니다. ( capture-default  =’  여러분이 대입연산자나 복사 초기화 Foo foo = bar  생각하게 하기 위함입니다;

사실 복사는 위의 예제에서 m_a(a) 같이 한번에 초기화 하기 위해 만들어 졌습니다.

 

C:\Temp>type defaultcapturekittybyvalue.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

int main() {

    vector<int> v;

 

    for (int i = 0; i < 10; ++i) {

        v.push_back(i);

    }

 

    int x = 0;

    int y = 0;

 

    cout << "Input: ";

    cin >> x >> y; // EVIL!

 

    v.erase(remove_if(v.begin(), v.end(), [=](int n) { returnx < n && n < y; }), v.end());

 

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

    cout << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 defaultcapturekittybyvalue.cpp > NUL && defaultcapturekittybyvalue

Input: 4 7

0 1 2 3 4 7 8 9

 

 

 

컴파일러는 람다 구문 내에 있는 x y 보고, main()함수에 있는 x y 값을 캡쳐 합니다.

위에서 (a)항목에서 말한 람다의 함수 호출 연산자( () 연산자 기본적으로const이기 때문에 캡쳐한 복사본(원본) 수정할  없지만,  람다 ()연산자 함수 내부에서 mutable(변하기 쉬운키워드를 사용하여 non-const 만들면됩니다.

 

C:\Temp>type capturekittybymutablevalue.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

int main() {

    vector<int> v;

 

    for (int i = 0; i < 10; ++i) {

        v.push_back(i);

    }

 

    int x = 1;

    int y = 1;

 

    for_each(v.begin(), v.end(), [=](int& r) mutable {

        const int old = r;

 

        r *= x * y;

 

        x = y;

        y = old;

    });

 

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

    cout << endl;

 

    cout << x << ", " << y << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 capturekittybymutablevalue.cpp > NUL && capturekittybymutablevalue

0 0 0 6 24 60 120 210 336 504

1, 1

 

 

v 있는  값에 이전의 x,y곱을 곱하는 동작을 합니다.

 (이전의 모든 요소들과 곱해주도록 partial_sum() 함수나이전의 요소들과바로 곱해주도록 adjacent_difference() 함수를 이용해서 구현할수  없어서예제처럼 구현이 되어있습니다.)  위에서 말한 항목 “(d) 캡쳐된 복사본을 원본의 지역변수에 적용되지 않는다”  기억하세요.

 

위에 (b),(C),(d) 약속을 우회할 방법을 알고 싶다면복사를 하지 않고 람다내부에서 값을 변경하는 것을 관찰하는 방법람다함수 내부에서 값을 바꿀 있지 않을까요이럴 경우 참조(reference) 값을 캡쳐하는 방법을 생각 했을겁니다.  이렇게 하는 방법은 람다-소개자(lambda introducer) [&x, &y]하면 됩니다( [&x, &y]  X& x, Y& y 생각하세요포인터의 전달이 아닌참조(Reference)입니다.) :

 

C:\Temp>type capturekittybyreference.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

int main() {

    vector<int> v;

 

    for (int i = 0; i < 10; ++i) {

        v.push_back(i);

    }

 

    int x = 1;

    int y = 1;

 

    for_each(v.begin(), v.end(), [&x, &y](int& r) {

        const int old = r;

 

        r *= x * y;

 

        x = y;

        y = old;

    });

 

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

    cout << endl;

 

    cout << x << ", " << y << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 capturekittybyreference.cpp > NUL && capturekittybyreference

0 0 0 6 24 60 120 210 336 504

8, 9

 

 

위의 예제 capturekittybymutablevalue.cpp  다른 점은

(1)람다-소개자 모양lambda-introducer) [&x, &y]

(2) mutable 키워드가 없습니다.

(3) main()함수 지역 변수 x,y 값이 람다함수 내부에서 변경된 것이 main()함수에서도 적용되었습니다.

 세가지 입니다.

 

 

위의 코드를 현재 C++ 구현 한다면 아래와 같이 구현할  있습니다.:

C:\Temp>type capturekittybyreference98.cpp

#include <algorithm>

#include <iostream>

#include <iterator>

#include <ostream>

#include <vector>

using namespace std;

 

#pragma warning(push)

#pragma warning(disable: 4512) // assignment operator could not be generated

 

class LambdaFunctor {

public:

    LambdaFunctor(int& a, int& b) : m_a(a), m_b(b) { }

 

    void operator()(int& r) const {

        const int old = r;

 

        r *= m_a * m_b;

 

        m_a = m_b;

        m_b = old;

    }

 

private:

    int& m_a;

    int& m_b;

};

 

#pragma warning(pop)

 

int main() {

    vector<int> v;

 

    for (int i = 0; i < 10; ++i) {

        v.push_back(i);

    }

 

    int x = 1;

    int y = 1;

 

    for_each(v.begin(), v.end(), LambdaFunctor(x, y));

 

    copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));

    cout << endl;

 

    cout << x << ", " << y << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 capturekittybyreference98.cpp > NUL && capturekittybyreference98

0 0 0 6 24 60 120 210 336 504

8, 9

 

 

 

(람다를 사용하면 , 컴파일러는 자동으로 C4512 경고를 꺼줍니다.)

  

지역 변수를 참조로 캡쳐하면함수 객체는 참조(reference) 자신의 참조(reference) 멤버변수에 저장합니다.

 이렇게 하면 함수 객체 () 함수에서 변경된 값이 적용이 되는 겁니다.

(함수 객체의 ()함수  const 것에 주의하세요우리는(VC++ 컴파일러팀) mutable이라 하지 않습니다. const 붙인 것은 단순히  함수객체의 멤버 데이터의 변경을 막기 위함 입니다멤버데이터들은 참조하는   변경할수 없고 멤버 데이터들이 참조하는 값을 변경할  있습니다. Const 아닌 함수 객체는 얕은 복사입니다.)

 

물론만약 람다함수 객체가 참조로 캡쳐된 지역변수들 보다 오래 생존(instantiate) 하게 되면 프로그램은 죽게 됩니다(crashtrocity :  뭔소리야?!!).

 

또한기본 캡쳐를 사용할 수도 있습니다. ;  [&]  참조로 모든 변수를 캡쳐한다 의미 합니다.

 

만약  개는 참조로하고  개는 값으로 캡쳐하고 싶을땐 어떻게 할까요?

[a, b, c, &d, e, &f, g] 방법을 생각하겠지만여러분들은 capture-default  지정하고 특정 지역변수들에 대해 오버라이드   있습니다.

아래 예제는 위에 나온 예제capturekittybymutablevalue.cpp  수정한 입니다.:

  

C:\Temp>type overridekitty.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

int main() {

    vector<int> v;

 

    for (int i = 0; i < 10; ++i) {

        v.push_back(i);

    }

 

    int sum = 0;

    int product = 1;

 

    int x = 1;

    int y = 1;

 

    for_each(v.begin(), v.end(), [=, &sum, &product](int& r)mutable {

        sum += r;

 

        if (r != 0) {

            product *= r;

        }

 

        const int old = r;

 

        r *= x * y;

 

        x = y;

        y = old;

    });

 

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

    cout << endl;

 

    cout << "sum: " << sum << ", product: " << product << endl;

    cout << "x: " << x << ", y: " << y << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 overridekitty.cpp && overridekitty

overridekitty.cpp

0 0 0 6 24 60 120 210 336 504

sum: 45, product: 362880

x: 1, y: 1

 

 

여기서는 x,y 값으로 캡쳐하고, (람다 내부에서만 수정되어져야 하기 때문) sum, produce 참조로 캡쳐 했습니다반대로 lambda-introducer  [&, x, y]  해도 같은 같은 결과 입니다.

 

그럼 this 는 어떻게 할 까요?

C:\Temp>type memberkitty.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

class Kitty {

public:

    explicit Kitty(int toys) : m_toys(toys) { }

 

    void meow(const vector<int>& v) const {

        for_each(v.begin(), v.end(), [m_toys](int n) {

            cout << "If you gave me " << n << " toys, I would have " << n + m_toys << " toys total." << endl;

        });

    }

 

private:

    int m_toys;

};

 

int main() {

    vector<int> v;

 

    for (int i = 0; i < 3; ++i) {

        v.push_back(i);

    }

 

    Kitty k(5);

    k.meow(v);

}

 

C:\Temp>cl /EHsc /nologo /W4 memberkitty.cpp

memberkitty.cpp

memberkitty.cpp(12) : error C3480: 'Kitty::m_toys': a lambda capture variable must be from an enclosing function scope

 

 

  

람다 수식 문법은 지역변수를 캡쳐하는건 허용하지만 멤버 변수의 캡쳐는 허용하지 않습니다.  대신 특별히 this 포인터를 캡쳐   있습니다. :

C:\Temp>type workingmemberkitty.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

class Kitty {

public:

    explicit Kitty(int toys) : m_toys(toys) { }

 

    void meow(const vector<int>& v) const {

        for_each(v.begin(), v.end(), [this](int n) {

            cout << "If you gave me " << n << " toys, I would have " << n + m_toys << " toys total." << endl;

        });

    }

 

private:

    int m_toys;

};

 

int main() {

    vector<int> v;

 

    for (int i = 0; i < 3; ++i) {

        v.push_back(i);

    }

 

    Kitty k(5);

    k.meow(v);

}

 

C:\Temp>cl /EHsc /nologo /W4 workingmemberkitty.cpp > NUL && workingmemberkitty

If you gave me 0 toys, I would have 5 toys total.

If you gave me 1 toys, I would have 6 toys total.

If you gave me 2 toys, I would have 7 toys total.

 

 

this 캡쳐하면 m_toys멤버 변수는 암시적으로 this->m_toys 의미 한다는 것을 생각   있습니다.  (람다 수식 내부에선, this 캡쳐된 this의미하지 람다 객체의 this포인터를 의미하지 않습니다. : 람다함수의 this 포인터에는 접근할  없습니다.)

 

this 암시적으로 캡쳐할  있습니다:

C:\Temp>type implicitmemberkitty.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

class Kitty {

public:

    explicit Kitty(int toys) : m_toys(toys) { }

 

    void meow(const vector<int>& v) const {

        for_each(v.begin(), v.end(), [=](int n) {

            cout << "If you gave me " << n << " toys, I would have " << n + m_toys << " toys total." << endl;

        });

    }

 

private:

    int m_toys;

};

 

int main() {

    vector<int> v;

 

    for (int i = 0; i < 3; ++i) {

        v.push_back(i);

    }

 

    Kitty k(5);

    k.meow(v);

}

 

C:\Temp>cl /EHsc /nologo /W4 implicitmemberkitty.cpp > NUL && implicitmemberkitty

If you gave me 0 toys, I would have 5 toys total.

If you gave me 1 toys, I would have 6 toys total.

If you gave me 2 toys, I would have 7 toys total.

 

 

 

[&] 할수 있지만 ,  this 포함 되지 않습니다.(항상 값으로 전달됩니다.) , [&this] 안됩니다.

 

람다 소개자(lambda-introducer) 아무런 값을 넣고 싶지 않으면, lambda-parameter-declaration 전체는 생략 됩니다. :

C:\Temp>type nullarykitty.cpp

#include <algorithm>

#include <iostream>

#include <iterator>

#include <ostream>

#include <vector>

using namespace std;

 

int main() {

    vector<int> v;

 

    int i = 0;

 

    generate_n(back_inserter(v), 10, [&] { return i++; });

 

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

    cout << endl;

 

    cout << "i: " << i << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 nullarykitty.cpp > NUL && nullarykitty

0 1 2 3 4 5 6 7 8 9

i: 10

 

 

 

 [&]() { return i++; } 비교해서 2문자( () )  빠져 있습니다 . 

lambda-parameter-declaration  생략하는  여러분들 마음입니다.

 

 

장난 삼아 아래의 코드는 C++0x 에서 유효한 코드입니다.:

C:\Temp>type nokitty.cpp

int main() {

    [](){}();

    []{}();

}

 

 

 

위의 예제는 아무런 동작을 하지 않는  개의 람다를 생성합니다.

( 번째는 lambda-parameter-declaration 있고  번째는 없습니다.)

 

추가적으로 사용할  있는 lambda-parameter-declaration  문법적으로아래와 같이 구성되어있습니다. :

 

( lambda-parameter-declaration-listopt ) mutableopt exception-specificationopt lambda-return-type-clauseopt

 

그래서 mutable 이나 ->리턴타입  지정하고 싶으면 lambsa-introducer( [] )  사이에  공간이 필요 합니다.

 

마지막으로람다는 보통의 함수 객체를 만들어 내기 때문에 , 함수 객체들을 tr1::function  보관  수도 있습니다.:

C:\Temp>type tr1kitty.cpp

#include <algorithm>

#include <functional>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

using namespace std::tr1;

 

void meow(const vector<int>& v, const function<void (int)>& f) {

    for_each(v.begin(), v.end(), f);

    cout << endl;

}

 

int main() {

    vector<int> v;

 

    for (int i = 0; i < 10; ++i) {

        v.push_back(i);

    }

 

    meow(v, [](int n) { cout << n << " "; });

    meow(v, [](int n) { cout << n * n << " "; });

 

    function<void (int)> g = [](int n) { cout << n * n * n << " "; };

 

    meow(v, g);

}

 

C:\Temp>cl /EHsc /nologo /W4 tr1kitty.cpp > NUL && tr1kitty

0 1 2 3 4 5 6 7 8 9

0 1 4 9 16 25 36 49 64 81

0 1 8 27 64 125 216 343 512 729

 

 

반응형
반응형


http://www.codeguru.com/cpp/cpp/cpp_managed/general/article.php/c16355/Using-WPF-with-Managed-C.htm#page-1



1. Introduction

The purpose of this article is two folds. At the first half we discuss what WPF is. In addition we studied why and how to program WPF using Managed C++ and high level overview of WPF architecture. Latter we scratch the surface of Loan Amortization with one working example of Loan Amortization in WPF using C++.

2. What is WPF?

Before going to study the WPF one might ask a question that what is WPF? WPF is abbreviation of "Window Presentation Foundation". It is a next generation presentation system for building window client application that can be run stand alone as well as in a Web Browser (i.e. XBAP Application). WPF is based on .Net environment, it means it is a managed code and theoretically can be written with any .Net based language such as Visual C#, VB.Net and Managed C++. WPF introduced with .Net 3.0 with few other important technologies such as Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF), but here we are going to study only WPF.

WPF is the latest Microsoft technologies to create user interface. It was introduced with .Net 3.0 and then improved in .Net 3.5 and .Net 4.0 (Beta as of now). It does not depend on Windows Standard control; it draws everything from DirectX technology and takes full advantage of 3D graphics and hardware accelerator if available.

Most of the programmer thought that WPF is a feature of Visual C# and VB.Net can be done only in these languages. Although writing WPF programs in these languages are quite easy and fun, but it is not limited to only this. WPF is in fact a feature of .Net introduced with its version 3.5; therefore technically any .Net language can use it.

If this is a case then why there are so many WPF samples written only in C# and VB.Net codes even in MSDN? The best answer might be because of XAML. When using C# or VB.Net then we can take full advantage of XAML, which is not available in VC++.Net. It means when you are trying to write WPF code in Managed C++, then you are on your own and have to write code for everything. It may be a daunting task but not impossible and in fact there are few samples available with Microsoft SDK such as PlotPanel, RadialPanel, CustomPanel etc.

2.1. Why Managed C++ for WPF?

Next question is why should we use Managed C++ in Visual C++ to write WPF application when we can do the same thing in C# or VB.Net with XAML? There can be different reasons for it.

  • You lots of code base written in VC++ unmanaged code and it is not possible to rewrite everything in C#. You want to take advantage of both managed and unmanaged code in your project, such as using MFC document view architecture with rich user interface of WPF without creating any new DLL in C#.
  • Portion of your programs should be optimized for speed and for performance reason you write unmanaged code for it. WPF internally used the same technique for performance reason to call DirectX.
  • You want to hide the implementation of some portion of your program and or algorithm so no one can reverse engineer and write it as unmanaged code so no one can reverse engineer your code using ildasm.
  • Just for fun.

2.2. WPF Programming in VC++

To create simplest WPF program using Managed C++, you have to include reference of .Net components named windowsbase.dll, presentationcore.dll and presentationframeworkd.dll. In addition the program must be compiled using /clr switch because it is a managed code. Here is a diagram to show one project that has added references of these three DLL. To add the reference, right click on the project in the Solution Explorer tree and select "Reference..." from there.

If we want to create a simple windows based program then it would be something like this.

  1. #include <windows.h>
  2. using namespace System::Windows;
  3.  
  4. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  5. LPSTR lpCmd, int nCmd)
  6. {
  7. MessageBox::Show("Hello World");
  8. }
This program does nothing more than simply display one message box. We can further shorten the program by using main instead of WinMain and avoid including windows.h header file altogether, but in that case we will see the black console window behind the message box.

If we want to make something more useful and interesting then we have to create objects of at least two classes Window and Application. But remember there can be only one object of Application class in the whole program. Here is the simplest program to show the usage of Window and Application class.

  1. #include <windows.h>
  2. using namespace System;
  3. using namespace System::Windows;
  4.  
  5. [STAThread]
  6. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  7. LPSTR lpCmd, int nCmd)
  8. {
  9. Window^ win = gcnew Window();
  10. win->Title = "Hello World";
  11.  
  12. Application^ app = gcnew Application();
  13. app->Run(win);
  14. }
The output of this program is a blank window with a title "Hello World". Here Application class is used to start the WPF application, manage the state of application and application level variables and information, but there is no output of it. It is Windows class that is responsible to draw window on the screen. Run method should be the last method call in the program, because this method won't return until the program close. Return value of Run method is application exit code return to the operating system.

It is not necessary to pass the window object as a parameter in the run function of application class. We can call Run function without any parameter, but if we call the Run function without any parameter then we have to call the Show or ShowDilaog function of Window class before calling the Run. Difference between Show and ShowDialog is Show display the model dialog, on the other hand ShowDialog display the modeless dialog. For our simple application it doesn't make any difference.

You can inherit your classes from Window and Application classes to store some application specific or window specific information. But remember you class must be inherited using the "ref" keyword and use "gcnew" keyword to create an instance of it on managed heap. Here is a simple program to show the usage of user inherited Window and Application classes.

  1. #include <windows.h>
  2. using namespace System;
  3. using namespace System::Windows;
  4.  
  5. public ref class MyWindow : public Window
  6. {
  7. public:
  8. MyWindow()
  9. {
  10. Title = "Hello World";
  11. }
  12. };
  13.  
  14. public ref class MyApplication : public Application
  15. {
  16. };
  17.  
  18. [STAThread]
  19. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  20. LPSTR lpCmd, int nCmd)
  21. {
  22. MyWindow^ win = gcnew MyWindow();
  23.  
  24. MyApplication^ app = gcnew MyApplication();
  25. app->Run(win);
  26. }
Output of this program is same as the previous one. In this program we can store all the application specific information in MyApplication class and Window specific information in MyWindow class. For example we set the title of the window in the constructor rather than in main after creating the object of it. We can also set other properties of window such as its back ground color, size, etc in the same place i.e. constructor.

These classes and their usages looks quite familiar with MFC. In MFC based application we also need object of two classes named CWinApp and CWnd. Similarly we create only one object of CWinApp based class and call the run method of CWinApp.

2.3. WPF Class Hierarchy

As we have seen before that to make smallest WPF application that display its own window we have to create objects of at least two classes named Window and Application. Before going further let's take a look at these two classes in little bit more detail. Here is a class diagram to show the inheritance chain for Application and Window class.



반응형
반응형

http://gpgstudy.com/forum/viewtopic.php?t=23376



반응형

'프로그래밍(Programming) > Script, lua' 카테고리의 다른 글

Lua, Sol, the basics  (0) 2022.03.03
Lua : property  (0) 2021.10.13
Lua 한페이지로 배우기  (0) 2021.06.24
반응형
http://blog.naver.com/kaydenkross/30167616348

자식 디폴트 복사생성자는
부모 디폴트 복사상성자를 자동으로 호출한다.
 
하지만 자식복사 생성자를 사용자 정의로 만들어주면 이 복사생성자는 부모의 디폴트 생성자를 호출한다.

자식클래서에서 어떤 생성자를 만들건간에, 반드시 멤버이니셜 라이져로 부모 생성자를
호출해 줘야만한다. (이니셜라이져 사용안할시에는 부모의 디폴트 생성자를 호출)

자식 디폴트 대입연산자는 부모디폴트 대입연산자를 호출한다.
자식 디폴트 연산자를 임의로 만들경우에는 반드시 그 안에 부모 대입연산자 호출부가 들어가야한다.




반응형
반응형

http://blog.naver.com/thehighway/150011611500



반응형
반응형

http://gdiary-tmp.tistory.com/8


UB : OS (정확히는 MS Winows 계열) 의 버전 정보를 알아내는 함수.

XP / Vista / 7    각기 다른 세종류의 Windows가 난무(?)하는 요즘,
현재 시스템의 Windows 버전에 대한 정보를 알아오기 위한 방법.


OSVERSIONINFO osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);


위 4라인만 돌려주면  osvi 라는 변수에 Windows의 정보가 들어가게 된다.

대충 사용할수 있는 변수를 보면

메이저버전 : osvi.dwMajorVersion
마이너버전 : osvi.dwMinorVersion
빌드넘버 : osvi.dwBuildNumber

Windows 7의 경우  메이저(6), 마이너(1) 이며 Vista 의 경우 메이저(6), 마이너(0) 이다.






좀더 자세한 것은


//ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.ko/sysinfo/base/osversioninfo_str.htm


에 나옴

반응형
반응형


tcmalloc, jemalloc 그리고 nedmalloc


복사

http://blog.naver.com/sorkelf/40189432780


TCMalloc

 

TCMalloc은 (Thread - Caching Memory Allocation) 의 약자로 구글에서 만든 메모리 할당 라이브러리 이다.

 

중앙메모리 관리자와 스레드별 메모리 관리자를 구분하여 32K이하의 작은 크기인경우에 메모리 할당/해제 요청은 스레드별 메모리 관리자가, 부족할 경우 중앙 메모리 관리자에서 얻어오는 형태를 띄고 있다.

메모리 할당시 불필요한 동기화 과정이 거의 없으므로 보다 좋은 성능향상을 얻을 수 있다.

 

 

 

TCMalloc에 문서에서는 32k 이하의 작은 크기인 경우에 대한 메모리의 할당 해제가 ptmalloc2보다 약 6배 빠르다고 하고 있다.


사용법은 매우 간단하다.

 

아래 사이트에서 최신 버전에 구글 퍼포먼스툴을 다운받고

 

https://code.google.com/p/gperftools/downloads/detail?name=gperftools-2.0.zip

 

프로젝트 빌드를 한뒤 생성되는 라이브러리를 사용하려는 해당 프로젝트에 링크 시켜주면 끝이다.

 

아래는 사용법에 관한 원문

 

Usage

To use TCmalloc, just link tcmalloc into your application via the "-ltcmalloc" linker flag.

You can use tcmalloc in applications you didn't compile yourself, by using LD_PRELOAD:

   $ LD_PRELOAD="/usr/lib/libtcmalloc.so" <binary>
</binary>

LD_PRELOAD is tricky, and we don't necessarily recommend this mode of usage.

 

 

또한 구글 퍼포먼스 툴에서는 

Heap Checker, Heap Profiler, CPU Profiler의 TCMalloc 이외에도 메모리 누수 디버깅, 프로파일링에 좋은 툴들을 제공하고 있다.

레퍼런스도 많이 존재하며 임베디드 및 iOS도 지원해서 보편적으로 사용중에 있다.

 

 

NedMalloc

 

Ogre3D에 새로운 메모리 할당자로 채택 된 NedMalloc은 Hoard, ptmalloc2 보다 빠르다고 한다.

c++ 코드로 이루어져있으며 윈도우에 최적화 되어 있다.

파일도 3개만 추가하면 되므로 프로젝트에 적용하기 용이하다..

 

 

To Use:

Drop in nedmalloc.h, nedmalloc.c and malloc.c.h into your project.

Configure using the instructions in nedmalloc.h. Run and enjoy.

 

To test, compile test.c. It will run a comparison between your system

allocator and nedalloc and tell you how much faster nedalloc is. It also

serves as an example of usage.

 

 

http://www.nedprod.com/programs/portable/nedmalloc/

 

홈페이지에서 말하는건.. tcmalloc은 서버프로세스에서 사용하는것이 좋음

 

 

JEMalloc

 

JEMalloc은 (Jason Evans)가 만들어서 JEMalloc이라 부르며 현재 페이스 북, 파이어폭스에서 사용하고 있는 메모리 할당 라이브러리이다.

http://www.canonware.com/jemalloc/download.html

 

 

 

위에 나와있는 도표 중 jemalloc이 가장 좋은 성능을 보이고 있지만, tcmalloc과의 큰 차이를 보이고 있진 않다.

Jason Evans도 실코어 8개 이상 컴퓨터에서는 jemalloc이 더 좋은 성능을 보인다고 이야기 해보았을때 아직까지는 두 개의 성능이 크게 차이 나지는 않는 듯 하다..


스택 오버플로우에 한 답변에는 아래와 같은 이야기가 있다..

 

tcmalloc은 메모리 풀을 사용하는 등의 정적인 스레드일 경우 효과적이며

jemalloc은 스레드를 생성하거나 파기할때의 효과적이다.

 

두개 다 프로젝트에서 사용해보고 더 나은 것을 찾는게 제일 낫지 싶다.

 

 그 외 조사해볼 라이브러리 - LKMalloc, HOARD, PTMalloc3, OpenBSD 등등..


반응형
반응형
http://blog.naver.com/swoosungi/90024620229

freetyped3d-swoosungi.zip




자존심님 이야기를 듣고 FreeType에 관해 찾아보았습니다.

일단 참고 홈페이지는 http://www.freetype.org/ 여기더군요...

프리타입에 관해 인터넷에서 자료를 찾아보니...

윈도우 보다는 리눅스에서 트루타입 폰트 레스터라이져를 위해

사용하는 라이브러리 같더군요... 그래서 링크를 찾아보니

리눅스용 라이브러리가 가장먼저 눈에 뛰인듯...

 

윈도우용 라이브러리는 http://gnuwin32.sourceforge.net/packages/freetype.htm

여기서 다운받는걸로 되있습니다.

http://prdownloads.sourceforge.net/gnuwin32/freetype-2.1.10.exe?download

 

여기서 freetype-2.1.10.exe 이 파일을 받고 설치하면

윈도우용 프리타입 sdk를 사용할수 있습니다.

 

추가로 프리타입라이브러리를 사용하는 어플리케이션의 실행파일은

freetype6.dll, zlib1.dll을 같이 필요로 합니다.

 

흠... 윈도우용 튜토리얼을 처음에 찾아봤는데... 찾기 쉽지않더군요...

gpg랑 데브피아에도 없고... 그래서 dx의 텍스쳐에 바로

트루타입폰트를 찍는 예제를 만들어보았습니다.

 

아 아크로드가 이 프리타입라이브러리를 사용하더군요 보니깐.. ^^;;;

 

추신 - 이소스는 프리타입에 관한 가장기본적인 기능만 튜토리얼로 만들어본겁니다.

아직 손봐야할 기능들이 많이 있습니다.

 

더 참고하시고 싶은분은 위사이트 프리타입 튜토리얼을 참조하세요



반응형
반응형





class B{

public :

B(){

std::cout<<"B의 생성자 호출"<<std::endl;

}

~B(){

std::cout<<"B의 소멸자 호출"<<std::endl;

}

};


template<class T>

T* alloc(int _size)

{

void* buff = malloc(_size);

return new(buff) T;

}


template<class T>

void dealloc(T* _p)

{

_p->~T();

free(_p);

}




int main(){



B* addrs =  alloc<B>( sizeof(B) );


dealloc(addrs);


....

}






http://drunkenpsycho.tistory.com/13 에서 일부 발췌



malloc / new 차이점

  C++에서는 기본적으로 malloc과 new 모두 사용이 가능하다. 그렇다면 차이점은 어떤 것이 있고, 어떠한 경우에 malloc이나 new를 선택하느냐를 알아보자.

  1) malloc은 기본적으로 라이브러리 제공 함수로, 함수 콜을 요청하게 된다. 하지만, new는 C++ 언어에서 제공하는 기본 키워드로, 별도의 라이브러리 추가없이 바로 사용이 가능하다.

  2) malloc은 기본적으로 사이즈를 매개변수로 받고, 리턴타입이 void *형이므로 sizeof 와 캐스트 연산자의 도움을 받아야 쉬운 코딩이 가능하다. 하지만 new는 할당할 타입을 지정하면, 알아서 할당할 타입의 포인터로 넘어오기 때문에, 할당할 타입과 같은 타입의 포인터 변수로 받아오기만 하면 끝이다.

  3) malloc은 메모리를 동적으로 할당하는 것만이 목적이므로 초기값을 지정해 줄 수 없지만, new의 경우는 할당과 동시에 초기화가 가능하다. 

  4) new 키워드는 생성자를 자동으로 호출하게 된다. 생성자는 객체를 자동으로 초기화 해주는 함수로, malloc과 new의 가장 큰 차이점이다. 





http://kldp.org/node/89335




template<class T> 
T* alloc(int _size)
{
      void * buff = malloc(_size);
      return new(buff) T;             // 생성자 호출됨. 
}




template<class T>
void destroy(T* p)
{
  p->~T();
  free(p);
}


반응형
반응형

혹시 가상함수는 Inline 되지 않는다고 생각하는 분들도 아마 있지 않을까 생각하는데 경우에 따라서 되기도 하고 안되기도 합니다.

 

되는 경우는 컴파일 시점에서 어떤 클래스의 가상함수를 사용하는지 알수 있느냐 입니다.

struct Base

{

    virtual void Function(void) const = 0:

};

 

struct Delived

{

    virtual void Function(void) const

    {

         std::cout << "Hello" << std::endl;

    }

};

 

int main(int, char**)

{

    Delived  delived;

    delived.Function();

     return 0;

}

위 코드의 경우 컴파일 시점에서 Delived 클래스의 Function 멤버를 사용한다는 것을 알 수 있디 때문에 가상함수인 Function Inline화 할 수 있습니다.

 

 

struct Base

{

    virtual void Function(void) const = 0:

};

 

void Call( Base &base )

{

    base.Function();

}

 

struct Delived:  public Base

{

    virtual void Function(void) const

    {

         std::cout << "Hello" << std::endl;

    }

};

 

int main(int, char**)

{

    Delived   delived;

    Call( delived );

     return 0;

}

그럼 이 코드의 Function 멤버는 Inline화 할 수 있을까요물론 됩니다이유는 이것도 컴파일 시점에서 어떤 클래스의 Function을 사용하는지 알 수 있기 때문입니다.

 

 

그러나 아래의 코드는 Function 멤버를 Inline화 할 수 없습니다.

struct Base

{

    virtual void Function(void) const = 0:

};

 

struct Delived:  public Base

{

    virtual void Function(void) const

    {

         std::cout << "Hello" << std::endl;

    }

};

 

struct Null  : public Base

{

    virtual void Function(void) const{}

};

 

int main( int argc, char** )

{

    Delived   delived;

    Null        null;

    

    Base  *base = 1 < argc ? static_cast<Base*>( &delived ) : static_cast<Base*>( &null );

     base->Function();

 

    return 0;

}

이유는 설명 안 해도 되겠죠? ^^

 

 

 

출처 : http://d.hatena.ne.jp/anonymouse_user/20120309/1331303971 

 


반응형
반응형
#pragma comment( linker, "/entry:WinMainCRTStartup /subsystem:console")

전 블로그에 올린거 같은기억이;;;

 



반응형
반응형

요즘 길가다 짬날때 보고 있는 C# .. 잼있네 ㅋㅋㅋ

http://www.csharp-station.com/ 여기 설명잘되있는사이트 추천! ㅋㅋ




Welcome

Welcome to C# Station!  This is a community site for people interested in applying .NET using the C# programming language.  We've been around since July 4th 2000 and have continued to grow over the years.  Items of interest include Articles, Books, Links, Documentation,  and Tutorials. More...

Who Operates this Site?

This site is owned and operated by Joe Mayo. Besides articles and tutorials on this site, Joe is a published author. His latest book, LINQ Programming is available now. Joe has a blog too. You can also follow Joe on Twitter.

Also check out What’s New in Visual C# 4.0? by Joe Mayo.

Source Code

If you would like to see an entire application written in C#, visit LINQ to Twitter, an open source LINQ Provider for the Twitter Micro-Blogging Service.

What is C#?

C# (pronounced "see sharp" or "C Sharp") is one of many .NET programming languages. It is object-oriented and allows you to build reusable components for a wide variety of application types Microsoft introduced C# on June 26th, 2000 and it became a v1.0 product on Feb 13th 2002.

C# is an evolution of the C and C++ family of languages. However, it borrows features from other programming languages, such as Delphi and Java. If you look at the most basic syntax of both C# and Java, the code looks very similar, but then again, the code looks a lot like C++ too, which is intentional. Developers often ask questions about why C# supports certain features or works in a certain way. The answer is often rooted in it's C++ heritage.

How Does a C# Application Run?

An important point is that C# is a "managed" language, meaning that it requires the .NET Common Language Runtime (CLR) to execute. Essentially, as an application that is written in C# executes, the CLR is managing memory, performing garbage collection, handling exceptions, and providing many more services that you, as a developer, don't have to write code for. The C# compiler produces Intermediate Language (IL) , rather than machine language, and the CLR understands IL. When the CLR sees the IL, it Just-In-Time (JIT) compiles it, method by method, into compiled machine code in memory and executes it. As mentiond previously, the CLR manages the code as it executes.

Because C# requires the CLR, you must have the CLR installed on your system. All new Windows operating systems ship with a version of the CLR and it is available via Windows Update for older systems. The CLR is part of the .NET, so if you see updates for the .NET Framework Runtime, it contains the CLR and .NET Framework Class Library (FCL). It follows that if you copy your C# application to another machine, then that machine must have the CLR installed too.

Does C# Have a Runtime Library?

Instead of a runtime library (such as APIs for file I/O, string handling, etc.) being dedicated to a single language, .NET ships with a .NET Framework Class Library (FCL), which includes literally tens of thousands of reusable objects. Since all .NET languages target the CLR with the same IL, all languages can use the FCL. This shortens the learning curve for any developer moving from one .NET language to another, but also means that Microsoft is able to add many more fea,tures because there is only one FCL, rather than a separate implementation for common features in every programming language. Similarly, 3rd party software vendors can write managed code that any .NET developer, regardless of language, can use. In addition to all of the services you would expect of a runtime library, such as collections, file I/O, networking, etc., the FCL includes the APIs for all of the other .NET technologies, such as for desktop and Web development.

What can I do with C#?

C# is only a programming language. However, because C# targets the CLR and has access to the entire FCL, there's a lot you can do. To get an idea of the possibilities, open the FCL and look at the available technologies. You can write desktop applications with Windows Forms,Windows Presentation Foundation (WPF), or even Console applications. For the Web, you can write ASP.NET and Silverlight applications in addition to enabling systems to communicate with Web Services with Windows Communications Foundation (WCF). When you need to access data, there is both ADO.NET and LINQ. Some of Microsoft's newest technologies include Windows 8Windows Phone 8, and Windows Windows Azure. Of course, these are only a few of the technologies available and as a general purpose programming language, you can do a lot more than this with C#.

How Do I Get Started?

By visiting this page and reading this far, you've already begun.  You can continue your journey with the Free C# Tutorial right here at C# Station. The C# Tutorial was created to help beginning developers and other professionals who need a quick on-ramp to the language.


반응형

+ Recent posts