함수에서 포인터를 사용하는 경우는 보통 다음과 같은 세가지 경우가 있다고 한다.

1. 매개 변수가 포인터
출력을 매개변수에 저장해서 보내는 것이 아닐까 추측하면 대부분 맞음.

void Add(int a, int b, int *c) {
	*c = a + b;
}

2. 반환 값을 여러 개 받고 싶은 경우
C++에서는 보통 반환값을 하나 밖에 받지 못한다. (ex: return X;)
함수를 실행 시켰을때 반환 값을 여러개 받(는 것처럼 하)고 싶다면,

void Add(int a, int b, int *c, int *d) {
	*c = a + b;
	*d = a - b;
}

와 같이 활용할 수 있다.

3. 크기가 엄청 큰 배열을 함수로 넘겨줄 때

bool IsEqual(const char str1[], const char str2[])
{
    int i=0;
    while(i<kMaxStr) {
        for(int j=0; j<kMaxStr;j++) {
            
            if(str1[i]!=str2[i])
                return false;
            else
                return true;
            i++;
        }
    }
    return true;
}

int main()
{
    const char str1[kMaxStr] = "stop";
    while (1)
    {
        char str2[kMaxStr];
        cin >> str2;

        if(IsEqual(str1, str2)) 
        {
            cout << "종료합니다.\n";
            break;            
        } else
            cout<<"계속합니다.\n";
    }

    return 0;
}

위의 IsEqual함수의 매개변수는 사실 배열이 아니라 포인터이다. 배열이 시작하는 곳의 주소.
sizeof(str1), sizeof(str2)를 해보면 둘다 포인터기 때문에 8바이트가 나온다. (크기가 100인 배열이면 100바이트가 나와야함) 문자의 배열 두개를 넘겨주는 것처럼 호출을 하고 있으나 내부적으로는 포인터이고, 아예

bool IsEqual(const char *str1, const char *str2)


 처럼 만드는 것도 괜찮다.

 

3번이 잘 이해가 안가서 wrtn.ai에게 물어보았고 답변 결과는 다음과 같았다.

C++에서 배열을 함수의 매개변수로 사용할 때, 실제로는 포인터가 사용됩니다. 이를 이해하기 위해선 배열과 포인터의 관계, 그리고 C++에서의 배열 인자 처리 방식에 대해 자세히 살펴볼 필요가 있습니다.
1. 배열과 포인터의 관계
C++에서 배열 이름은 배열의 첫 번째 요소를 가리키는 포인터로 사용될 수 있습니다. 예를 들어, int arr[10];이라는 배열이 있다면, arr은 &arr[0]을 의미하는 포인터로 해석될 수 있습니다. 배열의 이름 자체가 배열의 첫 번째 원소를 가리키는 주소로 변환됩니다.
2. 함수에서의 배열 인자
함수에 배열을 인자로 넘길 때, 배열의 크기 정보는 전달되지 않습니다. 대신, 배열의 이름(즉, 배열의 첫 번째 요소를 가리키는 포인터)만이 함수에 전달됩니다. 따라서, IsEqual(const char str1[], const char str2[]) 함수 선언에서 str1과 str2는 사실상 const char* str1, const char* str2와 동일하게 처리됩니다. 여기서 const 키워드는 포인터가 가리키는 데이터를 변경할 수 없음을 의미합니다.
3. 함수 내 배열 접근
함수 내에서 이 포인터(즉, 배열 이름)를 사용하여 배열의 각 요소에 접근할 수 있습니다. 포인터 산술을 사용하거나 배열 인덱싱 문법을 사용하여 이를 수행할 수 있으며, 이는 내부적으로 포인터 산술로 처리됩니다.
4. 결론
따라서, IsEqual 함수에서 const char str1[], const char str2[]를 매개변수로 사용할 때, 이들은 실제로는 const char* 타입의 포인터로 처리되며, 이 포인터들은 각각 문자열 str1과 str2의 첫 번째 문자를 가리키게 됩니다. 이를 통해 함수 내에서 문자열의 각 문자에 접근하여 비교할 수 있는 것입니다.
간단히 말해서, const char str1[]와 같은 매개변수는 포인터이며, 이는 함수에 전달될 때 배열의 크기 정보 없이 배열의 시작 주소만을 전달하기 때문입니다. 이런 방식으로 배열을 함수에 전달하는 것은 C++에서 일반적인 배열 처리 방법입니다.

'게임 개발 > C++언어' 카테고리의 다른 글

Ch03. 클래스의 기본  (0) 2020.12.23
C++언어 포스팅 계획  (0) 2020.12.23

열혈 C++의 8장. 상속과 다형성을 복습하고 가상함수에 대해 익혀오는 과제가 있었다.

두개의 소스코드를 볼 수 있는데, FunctionVirtualOverride.cpp와 EmployeeManager4.cpp였다.

우선 가상함수에 대해서 간단히 짚고 넘어가보자.

가상함수란 virtual 키워드를 일반적인 함수 앞에 붙임으로 그 함수가 오버라이딩을 할 수 있게 해준다.

오버라이딩을 통해 한가지 기능을 다른 여러가지 기능으로 쓸수 있는 '다형성'을 만들어낼 수 있다.

또한, 가상함수가 선언되고 나면, 이 함수를 오버라이딩 하는 다른 함수는 virtual을 붙이지 않아도 가상함수가 된다.

/* FunctionVirtualOverride.cpp 
   열혈 C++ 347-348p           */
 
#include <iostream>
using namespace std;

class First //First 클래스 생성
{
public:
	virtual void MyFunc() { cout<<"FirstFunc"<<endl; } // FirstFunc을 출력하는 가상함수 MyFunc
};

class Second: public First //First를 상속받는 Second 클래스 생성
{
public:
	virtual void MyFunc() { cout<<"SecondFunc"<<endl; } //굳이 추가하지 않아도 가상함수가 되나 가독성을 위해 선언을 넣기도 한다.
};

class Third: public Second //Second를 상속받는 Third 클래스 생성
{
public:
	virtual void MyFunc() { cout<<"ThirdFunc"<<endl; }
};

int main(void)
{
	Third * tptr = new Third(); //Third 객체를 생성해서 Third형 포인터 변수로 참조
    Second * sptr = tptr; //Second형 포인터 변수로 참조
    First * fptr = sptr; //First형 포인터 변수로 참조
    
    fptr->MyFunc();  //포인터변수로 MyFunc 함수 호출
    sptr->MyFunc();
    tptr->MyFunc();
    delete tptr;
    return 0;
}

가상함수를 호출할때, 포인터의 자료형을 기반으로 호출대상이 결정되지 않고, 포인터 변수가 실제로 가리키는 객체를 참조하여 호출의 대상을 결정한다.

/* EmployeeManager4.cpp
   열혈C++ 349-351p	 */

#include <iostream>
#include <cstring>
using namespace std;

class Employee
{
private:
	char name[100];
public:
	Employee(char * name)
    {
    	strcpy(this->name, name);
    }
	void ShowYourName() const
    {
    	cout<<"name: "<<name<<endl;
    }
    virtual int GetPay() const
    {
		return 0;
    }
    virtual void ShowSalaryInfo() const
    {}
};

class PermanentWorker : public Employee
{
private:
	int salary; //월 급여
public:
	PermanentWorker
};
class TemporaryWorker : public Employee
{

};
class SalesWorker : public PermanentWorker
{

};

class EmployeeHandler
{
private:
	Employee* emplist[50];
    {}
    void AddEmployee(Employee* emp)
    {
    	emplist[empNum++]=emp;
    }
    void ShowAllSalaryInfo() const
    {
    	for(int i=0; i<empNum; i++)
        	empList[i]->ShowSalaryInfo();
    }
    void ShowTotalSalary() const
    {
    	int sum=0;
        for(int i=0;i<empNum;i++)
        	sum+=empList[i]->GetPay();
        
        cout<<"salary sum: "<<sum<<endl;
    }
    ~EmployeeHandler()
    {
    	for(int i=0; i<empNum; i++)
        	delete empList[i];
    }
};

int main(void)
{
	//직원관리를 목적으로 설계된 컨트롤 클래스의 객체생성
    EmployeeHandler handler;
    
    //정규직 등록
    handler.AddEmployee(new PermanentWorker("KIM",1000));
	handler.AddEmployee(new PermanentWorker("LEE",1500));
    
    //임시직 등록
    TemporaryWorker* alba = new TemporaryWorker("Jung", 700);
    alba->AddWorkTime(5);
    handler.AddEmployee(alba);
    
    //영업직 등록
    SalesWorker* seller = new SalesWorker("Hong", 1000, 0.1);
    seller->AddSalesResult(7000);
	handler.AddEmployee(seller);
    
    //이번 달에 지불해야 할 급여의 정보
    handler.ShowAllSalaryInfo();
    
    //이번 달에 지불해야 할 급여의 총합
    handler.ShowTotalSalary();
    return 0;
]

'스터디 관련' 카테고리의 다른 글

CS스터디 02회차, ~06월 09일(목)  (0) 2022.06.09
CS스터디 01회차, ~06월 02일(목)  (0) 2022.06.02
2/3(수) 과제  (0) 2021.02.03
이번 스터디 과제,,  (0) 2020.12.31
소프트웨어 생명주기 6단계  (0) 2020.12.30

+ Recent posts