환경: c++20, 최적화 끔(-O0), 릴리즈 빌드
테스트 1
class A
{
public:
void foo()
{
printf("hello %d\n", var);
}
void set(int a)
{
this->var = a;
}
private:
int var = 100;
};
int main()
{
A a;
a.foo();
A b;
b = a;
b.foo();
}
아래는 IDA 디컴파일
int __fastcall main(int argc, const char **argv, const char **envp)
{
A a; // [rsp+20h] [rbp-18h] BYREF
A b; // [rsp+24h] [rbp-14h] BYREF
A::A(&a);
A::foo(&a);
A::A(&b);
b.var = a.var;
A::foo(&b);
return 0;
}
void __fastcall A::A(A *this)
{
this->var = 100;
}
void __fastcall A::foo(A *this)
{
printf("hello %d\n", (unsigned int)this->var);
}
스택에 a, b 각 4바이트씩 할당함 (멤버변수 사이즈)
클래스의 함수는 일반적인 함수로 취급 (함수명이 A::foo)
= 연산자에서 대입이 발생
테스트 2
private 변수만 늘리고 컴파일
private:
int var = 100;
int var2 = 200;
int var3 = 300;
아래는 IDA 디컴파일
int __fastcall main(int argc, const char **argv, const char **envp)
{
A a; // [rsp+20h] [rbp-48h] BYREF
A b; // [rsp+30h] [rbp-38h] BYREF
A::A(&a);
A::foo(&a);
A::A(&b);
qmemcpy(&b, &a, sizeof(b));
A::foo(&b);
return 0;
}
멤버 변수가 많으면 memcpy로 복사함
테스트 3
class A
{
public:
A& operator=(const A& a)
{
this->var = a.var;
return *this;
}
void foo()
{
printf("hello %d\n", var);
}
void set(int a)
{
this->var = a;
}
private:
int var = 100;
};
아래는 IDA 디컴파일
int __fastcall main(int argc, const char **argv, const char **envp)
{
A a; // [rsp+20h] [rbp-18h] BYREF
A b; // [rsp+24h] [rbp-14h] BYREF
A::A(&a);
A::foo(&a);
A::A(&b);
A::operator=(&b, &a);
A::foo(&b);
return 0;
}
A *__fastcall A::operator=(A *this, const A *a)
{
this->var = a->var;
return this;
}
기본 = 연산자가 내가 재정의한 operator=로 대체됨
operator=는 일반적인 함수로 취급 (함수명이 A::operator=)
테스트 4
class A
{
public:
A& daeip(const A& a)
{
this->var = a.var;
return *this;
}
A& operator=(const A& a)
{
this->var = a.var;
return *this;
}
void foo()
{
printf("hello %d\n", var);
}
void set(int a)
{
this->var = a;
}
private:
int var = 100;
};
int main()
{
A a;
a.foo();
A b;
b = a;
b.foo();
A c;
c.daeip(a);
}
아래는 IDA 디컴파일
int __fastcall main(int argc, const char **argv, const char **envp)
{
A a; // [rsp+20h] [rbp-28h] BYREF
A b; // [rsp+24h] [rbp-24h] BYREF
A c; // [rsp+28h] [rbp-20h] BYREF
A::A(&a);
A::foo(&a);
A::A(&b);
A::daeip(&b, &a);
A::foo(&b);
A::A(&c);
A::daeip(&c, &a);
return 0;
}
daeip 함수와 operator=는 기능적으로 동일함
최적화에 의해 operator= 가 삭제되고 daeip 함수로 통일됨
테스트 5
class A
{
public:
void daeip(const A& a)
{
this->var = a.var;
}
void operator=(const A& a)
{
this->var = a.var;
}
void foo()
{
printf("hello %d\n", var);
}
void set(int a)
{
this->var = a;
}
private:
int var = 100;
};
int main()
{
A a;
a.foo();
A b;
b = a;
b.foo();
A c;
c.daeip(a);
}
아래는 IDA 디컴파일
int __fastcall main(int argc, const char **argv, const char **envp)
{
A a; // [rsp+20h] [rbp-28h] BYREF
A b; // [rsp+24h] [rbp-24h] BYREF
A c; // [rsp+28h] [rbp-20h] BYREF
A::A(&a);
A::foo(&a);
A::A(&b);
A::daeip(&b, &a);
A::foo(&b);
A::A(&c);
A::daeip(&c, &a);
return 0;
}
b = a 처럼 단순 대입만 할 경우 operator=의 리턴값을 void로 해도 무방하다.
테스트6
class A
{
public:
void foo()
{
printf("hello %d\n", var);
}
void set(int a)
{
this->var = a;
}
private:
int var = 100;
};
int main()
{
A a;
a.foo();
A& b = a;
b.foo();
}
아래는 IDA 디컴파일
int __fastcall main(int argc, const char **argv, const char **envp)
{
A a; // [rsp+28h] [rbp-20h] BYREF
A::A(&a);
A::foo(&a);
A::foo(&a);
return 0;
}
A& b를 A a로 인식함
테스트7
class A
{
public:
A& operator=(const A& a)
{
this->var = a.var;
return *this;
}
void foo()
{
printf("hello %d\n", var);
}
void set(int a)
{
this->var = a;
}
private:
int var = 100;
};
아래는 IDA 디컴파일
int __fastcall main(int argc, const char **argv, const char **envp)
{
A a; // [rsp+28h] [rbp-20h] BYREF
A::A(&a);
A::foo(&a);
A::foo(&a);
return 0;
}
재정의를 해도 참조 연산 기능이 동일하여 바이너리 결과는 같음
'Windows > Dev' 카테고리의 다른 글
windows + mac 동시 개발 시 주의 사항 (0) | 2024.10.15 |
---|---|
[C++] 함수 const 선언 정리 (0) | 2024.09.12 |
[VC++] 문자열 복사, 이동 (0) | 2024.05.09 |
detours 빌드 및 적용 (0) | 2024.04.11 |
[Visual Studio 2022] curl 빌드 (0) | 2023.01.30 |