Skip to content

Commit

Permalink
Merge pull request #10 from m1ser4ble/adl
Browse files Browse the repository at this point in the history
Adl
  • Loading branch information
m1ser4ble authored Nov 2, 2024
2 parents 006f6fe + a6eee1d commit 2edfa27
Showing 1 changed file with 100 additions and 0 deletions.
100 changes: 100 additions & 0 deletions _posts/2022-11-08-adl.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
______________________________________________________________________

layout: single
title: "Access To Private Member in C++"
date: 2022-11-16 15:30:09 +0900
categories: C++, Langugage
toc: true
toc_sticky: true

______________________________________________________________________

C++ 처럼 memory address 를 직접적으로 다룰 수 있는 언어는 강제적 형변환을 통해 private member 에 접근하면 된다.
하지만, 이런 방식은 어떤 면에서 위험하다. 예를 들면, 어떤 라이브러리에 정의된 Class 의 private member 에 접근하고자 한다면
그 라이브러리의 버전이 변경되는 등의 이유로 Class 의 구조가 변경될 수 있다. 그럴 때마다 offset 을 계산해서 내 코드도 변경해줘야한다.
뿐만 아니라 실제로 undefined behavior 로 불리는 행위임. target class 가 vtable 을 갖고 있는지 등의 이유로 offset 은 언제든 변할 수 있음.

[litb](https://bloglitb.blogspot.com/2011/12/access-to-private-members-safer.html) 의 블로그에서 이런 문제점을 해결해주는 trick 을 소개하고 있다.

이 trick 을 이해하기 위해서는 friend keyword, member pointer, ADL 에 대해 알 필요가 있다. 하나하나 알아보도록 하자.

# friend keyword

friend keyword 는 이 기능 자체로 private member 에 접근할 수 있도록 허용해주는 것임. 그러나 이 키워드는 내부에서 문을 열어주는 느낌임.
예를 들면, 아래 코드는 friend 를 통해서 A 의 private member access 권한을 x 함수에게 줬다.

```cpp
Class A{
//private members
int x;
friend void x(A a); // open the door to function 'x'
}
void x(A a){
printf("%d\n",a.x);
}

```
library 에서는 이런 것을 아직 정의도 되지 않은 함수, class 에 대해 열어줄 리 만무하다.
# member pointer
:: 를 사용하면 우리는 클래스의 member 를 지칭할 수 있다. 예를 들면 아래 코드처럼 어떤 클래스(instance 가 아님) 의 멤버에 대한 refernece 를
변수(p) 에 담아 어떤 객체(instance) 의 멤버에 접근하는데 사용할 수 있다.
```c++
struct A {
A(int a):a(a) { }
int b;
private:
int a;
};
void test() {
auto p = &A::b;
std::cout << a.*p << std::endl;
}
```

그러면 이 방식을 바로 사용해서 private member 에 접근하면 안될까? 컴파일러에서 막는다.

> error: ‘int A::a’ is private within this context
하지만, test 함수에 대해 friend 선언을 하면 접근이 가능하다.

# ADL ( Argument Dependent Lookup)

Koenig lookup 라고도 불리는데, ADL 은 함수 호출 표현식에서 unqualified function name 을 찾는 일련의 규칙.
이름에서 알 수 있듯이, 기존의 scope 와 namesapce 에 더해 argument 의 namespace 를 참고해서 찾는다.

```cpp
#include <iostream>

int main()
{
std::cout << "Test\n"; // There is no operator<< in global namespace, but ADL
// examines std namespace because the left argument is in
// std and finds std::operator<<(std::ostream&, const char*)
operator<<(std::cout, "Test\n"); // Same, using function call notation

// However,
std::cout << endl; // Error: “endl” is not declared in this namespace.
// This is not a function call to endl(), so ADL does not apply

endl(std::cout); // OK: this is a function call: ADL examines std namespace
// because the argument of endl is in std, and finds std::endl

(endl)(std::cout); // Error: “endl” is not declared in this namespace.
// The sub-expression (endl) is not an unqualified-id
}
```

endl 함수는 인자의 namespace 가 std::cout 이니 std::endl() 을 이용하게 된다.

# Reference

- [stackoverflow](https://stackoverflow.com/questions/12993219/access-private-member-using-template-trick)
- [bloglitb](https://bloglitb.blogspot.com/2011/12/access-to-private-members-safer.html)
- [cpp reference](https://en.cppreference.com/w/cpp/language/adl)
- https://stackoverflow.com/questions/437250/friend-scope-in-c
- https://en.cppreference.com/w/cpp/language/friend
- https://www.ibm.com/docs/en/i/7.1?topic=only-friend-scope-c

0 comments on commit 2edfa27

Please sign in to comment.