참조자 형식

참조자 형식은 겉으로 보기엔 포인터와 다르지만 본질은 C언어의 포인터와 비슷하다. 

사용법은 "형식 &이름 = 원본"과 같이 반드시 선언과 동시에 초기화를 해줘야한다.

 

아래와 같이 nData의 참조자인 ref 변수를 만들었다. 그리고 메모리에서 &nData와 &ref를 둘다 까봤다.

결과는 008FFE2C로 둘다 같은 메모리 주소를 가지는 것 처럼 나온다. 그러니 ref변수에서 값을 20으로 바꾸면 원본인 nData의 값도 바뀌게 된다. 마치 포인터를 쓰는것과 같다.

	int nData = 10;
	int& ref = nData;

	ref = 20;
	cout << nData << endl;

	int* pData = &nData;
	*pData = 30;
	cout << nData << endl;

ref와 nData는 같은 주소

 

 

참조에 의한 호출, 주소에 의한 호출 예제
#include <iostream>
#include <string.h>
using namespace std;

class CIntArray
{
public:
	CIntArray(int nSize)
	{
		m_pnData = new int[nSize];
		memset(m_pnData, 0, sizeof(int) * nSize);
	}
	
	~CIntArray()
	{
		delete m_pnData;
	}
	
	int& operator[](int nIndex)
	{
		cout << "operator[]" << endl;
		return m_pnData[nIndex];
	}

private:
	int* m_pnData;
	int m_nSize;
};

int main()
{
	CIntArray arr(5);
	for (int i = 0; i < 5; ++i)
	{
		arr[i] = i * 10;
		cout << arr[i] << endl;
	}

	return 0;
}

 

CIntArray는 nSize 크기 만큼 int array를 만드는 클래스다(동적할당)

주목해야 할 점은 int& operator[](int nIndex)다.

여기서 int&는 참조형을 반환 하는데 무엇에 대한 참조형일까?

m_pnData 포인터의 요소 즉 int에 대한 참조형이다. 왜냐하면 m_pnData가 포인터인데 연속된 int형을 가르키는 포인터니깐!

 

여기서 참조를 빼면 "식이 수정할 수 있는 lvalue여야 합니다" 라는 에러가 난다.  이게 무슨 뜻일까?

nIndex가 0이라고 가정하면 m_pnData[0]에 해당하는 주소값(참조)을 넘겨야 그 주소값에 i * 10 값을 넣는데 &(참조)를 빼면 m_pnData[0]의 값을 return 하니 위와 같은 에러가 뜬다. 

참조는 곧 포인터라 했다 참조를 포인터로 고치는건 아주 간단한다.

 

참조에서 포인터로 변경
#include <iostream>
#include <string.h>
using namespace std;

class CIntArray
{
public:
	CIntArray(int nSize)
	{
		m_pnData = new int[nSize];
		memset(m_pnData, 0, sizeof(int) * nSize);
	}
	
	~CIntArray()
	{
		delete m_pnData;
	}
	
	int operator[](int nIndex) const
	{
		cout << "const" << endl;
		return m_pnData[nIndex];
	}
	
	int* operator[](int nIndex)
	{
		cout << "operator[]" << endl;
		return &m_pnData[nIndex];
	}

private:
	int* m_pnData;
	int m_nSize;
};

int main()
{
	CIntArray arr(5);
	for (int i = 0; i < 5; ++i)
	{
		*(arr[i]) = i * 10;
		cout << *(arr[i]) << endl;
	}

	return 0;
}

1. int& operator[]를 int*로 바꿨다.

2. return 할때 값이 아니라 주소로 바꿨다(&m_pnData[nIndex])

3. 대입할 때 *(arr[i])로 변경했다.

 

결론 : 참조는 포인터다.

'C++' 카테고리의 다른 글

C++ 깊은복사 얕은복사  (0) 2020.02.02
C++ 복사 생성자(참조형 파라미터)  (0) 2020.02.01
C++ this 포인터  (0) 2020.02.01
C에서 C++ 객체지향의 변환 과정  (0) 2020.01.28
C++ new 메모리 동적할당  (0) 2020.01.27
메모리 동적 할당

C언어에 malloc이 있다면 C++에는 new 연산자가 있다!

사용 방법은 정말 심플하다 

// 일반
형식 *변수이름 = new 형식;
delete 변수이름;

// 배열 형태
형식 *변수이름 = new 형식[요소개수];
delete[] 변수이름;
    // 일반
    
	int* pData = new int;
    int* pNewData = new int(10);

    *pData = 5;
    std::cout << *pData << std::endl;
    std::cout << *pNewData << std::endl;

    std::cout << "Hello World!\n";


    // 배열
    int* arr = new int[5];

    for (int i=0; i < 5; ++i)
    {
	    arr[i] = (i + 1) * 10;
    }

    for (int i=0; i < 5; ++i)
    {
	    std::cout << arr[i] << std::endl;
    }

    delete[] arr;

위와 같이 사용한다.

 

new 연산자와 malloc을 비교했을때 가장 큰 차이점은 메모리 크기를 정하지 않아도 알아서 해준다는 점이다.

그리고 하나 더 new 연산자는 객체의 생성자를 호출하고, delete 연산자는 객체의 소멸자를 호출한다는 점이다

 

'C++' 카테고리의 다른 글

C++ 깊은복사 얕은복사  (0) 2020.02.02
C++ 복사 생성자(참조형 파라미터)  (0) 2020.02.01
C++ this 포인터  (0) 2020.02.01
C에서 C++ 객체지향의 변환 과정  (0) 2020.01.28
C++ 참조자 형식(reference)  (0) 2020.01.27

전통적인 웹사이트(멀티 페이지) 로그인 방법은 Session을 이용하는 것이다.

로그인을 하면 서버와 브라우저 간에 세션이 생성되고 그 세션을 기반으로 Request가 안전 한지 판단한다.

 

React- The Complete Guide

React와 같은 SPA(싱글페이지)의 로그인 방법은 Session을 가지지 않는다. 

그대신 Token을 이용하는데 Restful 백엔드 서버에서 생성된 토큰을 로그인하면 받게 되고 이 토큰을 localStorage에 저장한다.

잘 저장해 뒀다가 서버로 데이터 요청 즉 Reuqest를 할 때 아까 발급 받은 Token을 같이 보낸다.

'React' 카테고리의 다른 글

React useCallback 이해하기  (0) 2022.01.13
React Redux 기본  (0) 2019.12.19
React Form input  (0) 2019.12.16
1. beforeinstallprompt 액션에서 deferedPrompt 변수에 evnet 할당
window.addEventListener('beforeinstallprompt', function(event) {
  console.log('beforeinstallprompt fired');
  event.preventDefault();
  deferredPrompt = event;
  return false;
});

 

2.  banner show 
function showBanner() {
  if (deferredPrompt) {
    deferredPrompt.prompt();

    deferredPrompt.userChoice.then(function(choiceResult) {
      console.log(choiceResult.outcome);

      if (choiceResult.outcome === 'dismissed') {
        console.log('User cancelled installation');
      } else {
        console.log('User added to home screen');
      }
    });

    deferredPrompt = null;
  }
}
배열은 O(N)이다.

배열은 삽입, 삭제, 검색을 할 때 O(N) 즉 loop를 한번 돈다. 아주 기본 중 기본..

C언어로 삽입, 삭제의 알고리즘 코드를 작성해보자.

 

 

배열의 삽입(우로밀착)
int nums[8];
size_t max_count = 0;

void insert_at(size_t index, int number)
{
	size_t i;

	// 우로밀착 코드
	for(i = max_count; i > index; i--)
	{
		nums[i] = nums[i-1];
	}

	nums[index] = number;
	++max_count;
}

void main()
{
	insert_at(0, 1);
	insert_at(0, 2);
	insert_at(0, 3);
	insert_at(0, 4);

	delete_at(0);
	size_t i;
	for (i = 0; i < MAX_NUMS; i++)
	{
		printf("%d\n", nums[i]);
	}
}

배열의 삽입이 0번째 인덱스 즉 가장 첫번째 자리에서 이뤄진다면 0번째 인덱스를 기준(현재 인덱스 포함)으로 오른쪽에 있는 모든 요소들은 우로밀착! 오른쪽으로 한 칸 이동 해야한다. 그래서 for loop가 필요하다.O(N)

 

 

배열의 삭제(좌로밀착)
void delete_at(size_t index)
{
	size_t i;
	for (i = index; i < max_count; i++)
	{
		nums[i] = nums[i + 1];
	}
	--max_count;
}

배열의 삭제가 0번째 인덱스에서 이뤄진다면 0번째 인덱스를 기준으로 좌로 한칸씩 밀착해야 한다.

'C' 카테고리의 다른 글

C언어 스택, 큐 자료구조 소스 코드  (0) 2020.02.26
C언어 빌드과정(컴파일)  (0) 2020.02.25
C언어 void*  (0) 2019.12.20
C 언어 변수에 함수 할당  (0) 2019.12.20
C언어 얕은복사 vs 깊은복사  (0) 2019.12.18

Django의 queryset을 JS에서 json으로 사용하고자 한다.

1. Django에서 queryset을 json으로 dump해야되고

2. JS에서는 그 dump한 데이터를 escape 처리 해주고 사용하면된다.

 

 

Django Queryset
    def get(self, request):
        car_id = request.GET.get('car_id', None)
        pallet_id = request.GET.get('pallet_id', None)
        ymd = request.GET.get('ymd', None)
        orderList: Manager = OrderList.objects.annotate(test=F('pallet__seq'))\
            .filter(Q(ymd=ymd), Q(pallet__car_id=car_id), Q(pallet_id=pallet_id)).values()
        rows = json.dumps(list(orderList))
        return render(request, 'release/releasetReport.html', {'rows': rows})

orderList 변수에 Queryset을 담는다. 그 내용은 values로 인해서 Model instance가 아니라 dictionary !

그다음 python에서 표준으로 제공하는 json을 불러와 dumps를 해준다. 이 때 orderList의 타입은 Queryset이라서 에러가 나니 list로 변환 해줘야 된다.

 

 

In Javascript
<script>
    let rows = {{ rows|safe }};
    console.log(rows);
</script>

js 파일에서 | safe 라는 템플릿 태그를 사용해주면 알아서 escape 해주고 배열로 사용할 수 있다.

 

아래의 결과값이 도출된다. js에서 편하게 쓰면 된다.

python에서 super란 정확히 무엇인가?? Django 프레임워크와 같이 상속을 이리저리 받고 MIXIN 쓰고 하면 헷갈린다.

 

 

super

super() alone returns a temporary object of the superclass that then allows you to call that superclass’s methods.

 

슈퍼(부모) 클래스의 임시 object를 리턴한다. 이 임시 object로 슈퍼 클래스의 메소드를 사용할 수 있다.!

그러니 super()라고 쓰면 부모 클래스의 object를 가져와서 부모 클래스의 say_hi() 같은 메소드를 사용할 수 있다는 말이다.

 

 

간단한 Super 예제(상속 전)
class Rectangle:
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def area(self):
        return self.length * self.width

    def perimeter(self):
        return 2 * self.length + 2 * self.width

class Square:
    def __init__(self, length):
        self.length = length

    def area(self):
        return self.length * self.length

    def perimeter(self):
        return 4 * self.length

square = Square(4)
print(square.area())

rectangle = Rectangle(2,4)
print(rectangle.area())

Square(정사각형)은 Rectangle(직사각형)의 특별한 케이스다. 그러므로 상속으로 코드를 줄일 수 있다.

 

간단한 Super 예제(상속 후)
class Rectangle:
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def area(self):
        return self.length * self.width

    def perimeter(self):
        return 2 * self.length + 2 * self.width

class Square(Rectangle):
    def __init__(self, length):
        super().__init__(length, length)
        
        
square = Square(4)
print(square.area())

rectangle = Rectangle(2,4)
print(rectangle.area())
        

이런식으로 Rectangle을 상속 받아서 사용하면 부모 클래스인 Rectangle의 are() 메소드를 사용할 수 있다.

Square의 __init__에서 super().__init__(length, length)라고 코딩했는데 이 호출에 따라서 Rectangle의 Class 오브젝트를 생성한다. 이렇게 Rectangle 오브젝트를 생성해야 area 메소드를 사용할 수 있다. 왜냐하면 area 메소드는 self.length와 self.width를 가지기 때문이다. (__init__을 호출해야 self.length, self.width 값이 정확히 생성됨)

 

 

super() vs super(클래스 이름, self)

위의  예제에서는 super()라고 포현했는데 다른 코드를 보면 super(Squre, self).__init__() 이런 식으로 표현하는 곳도 볼 수있다.

super()와 super(Squre, self) 은 무엇이 다를까?

사실 super는 두개의 파라미터를 받는데 처음은 하위클래스의 이름, 두번째는 하위클래스의 object다. 위의 예제에서는

super()와 super(Squre, self) 두개로 표현될 수 있는데 위의 예제의 경우에는 어떻게 표현하든 똑같다.

하지만 다중 상속 및 할머니 상속일 경우 의미가 살짝 다른데 첫번째 매개변수의 클래스 이름에 따라 super 가 탐색하는 범위가 달라진다.

 

 

부모의 부모(할머니)로 부터 상속
class Rectangle:
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def area(self):
        print('할머니 area')
        return self.length * self.width

    def perimeter(self):
        return 2 * self.length + 2 * self.width


class Square(Rectangle):
    def __init__(self, length):
        self.length = length
        super().__init__(length, length)

    def area(self):
        print('부모의 area')
        return self.length * self.length


class Cube(Square):
    def surface_area(self):
        face_area = super(Square, self).area()
        return face_area * 6

    def volume(self):
        face_area = super().area()
        return face_area * self.length


cube = Cube(3)
print(cube.surface_area())
# 할머니 area
# 54
print(cube.volume())
# 부모의 area
# 27

Cube Class의 surface_area와 volume 메소드는 모두 부모의 area 메소드가 필요하다.

이때 하나는 super(Square, self)를 하나는 super()를 사용했다. 

 

super(Square, self)를 사용한 surface_area는 할머니 즉 Rectangle에서 가져왔고 그냥 super()를 사용한 volume은 부모의 area를 사용했다.

 

아까 말했다 싶이 탐색범위가 달라진다고 했다 그러니깐 Square를 명시한 super는 Square의 부모로 부터 탐색한다. 그래서 Rectangle(할머니)의 area를 호출했다.

 

참고 사이트 : https://realpython.com/python-super/

int*  는 포인터 변수인데 그 가르키는 주소의 type이 int, char* 는 포인터 변수인데 가르키는 주소의 type이 char

그렇다면 void* 는 가르키는 주소의 type이 void 라는 말인데.. void 라는 애매모호한 type이 도대체 뭘까?

 

void*

void*는 바로 범용적 포인터 즉 일단 가르키고 본다. 어떤 포인터라도 대입이 가능하다 이말이다.

매개 변수로 void*를 사용하면 모든 포인터를 일단 받고 보겠다 이말이다.

 

하지만 역참조나 포인터 산술 연산을 할 때는 반드시 다른 포인터로 캐스팅해서 써야한다

void* var로 받고 나중에 역참조할때는 *(int* var) 이런식으로 해줘야한다!

 

 

C 언어 포큐아카데미

 

1. void* p에 float 포인터를 담았다. printf로 값을 출력할 때는 반드시 float 포인터로 캐스팅 해줘야한다.

2. 함수 add의 op1, op2는 void*로 일단 담았다. 역참조 할떄는 반드시 *(int*)op1, *(int*)op2 처럼 캐스팅 해줘야한다.

 

이렇게 캐스팅해주지 않으면 컴퓨터 입장에서 몇 바이트 만큼 읽으라는지 알 수가 없다!!

 

포큐아카데미 C언어 복습

'C' 카테고리의 다른 글

C언어 빌드과정(컴파일)  (0) 2020.02.25
C언어 배열 삽입, 삭제  (2) 2020.01.03
C 언어 변수에 함수 할당  (0) 2019.12.20
C언어 얕은복사 vs 깊은복사  (0) 2019.12.18
C언어 구조체  (0) 2019.12.18

+ Recent posts