2023.01.16 - 안드로이드 앱개발자 과정

CHA·2023년 1월 17일
0

C++



C++ 에서 전환된 부분



입출력

  • 출력 : std::cout << 출력할 데이터 << endl

    C언어에서는 출력의 대상에 따라 서식지정을 달리하였습니다. 하지만 C++에서는 그러한 과정이 불필요하며, 자동으로 처리해줍니다. 문법은 std::cout<< 출력할 데이터 << endl; 입니다. 또한 endl 은 개행을 처리해주는 키워드 입니다.

    ex)
    std::cout << "Hello World" << endl;
  • 입력 : std::cin >> 입력할 변수;

    출력과 마찬가지로 서식지정은 필요없습니다. 문법은 std::cin >> 입력할 변수; 입니다.

    ex)
    int val1,val2;
    std::cin >> val1 >> val2; // 연이은 데이터 입력도 가능하다!

함수 오버로딩

C++ 은 함수를 호출할 때, 함수의 이름전달되는 인자의 정보 를 동시에 참조하여 호출할 함수를 결정합니다. 따라서, 매개변수의 선언이 다르다면 동일한 이름의 함수를 정의할 수 있습니다. 이러한 형태의 함수 정의를 함수 오버로딩(Function Overoading) 이라 합니다. 만일, 반환형이 다르다면 어떨까요? 여기서는 함수의 이름과 매개변수의 선언은 같게 됩니다. 그렇기 때문에 같은 함수라고 판단하게 되어 오버로딩은 일어나지 않습니다.

ex)
int MyFunc(int num){
	num++;
    return num;
}
int MyFunc(int a,int b){
    return a+b;
}

void main(){
	MyFunc(20);		// MyFunc(int num); 의 호출
    MyFunc(10,20);	// MyFunc(int a,int b); 의 호출
}

함수 매개변수의 default 값

  • 매개변수에 설정하는 default 값의 의미

    C++ 에서는 매개변수를 선언하면서 초기값을 지정하는게 가능합니다. 다음 코드를 보겠습니다.

    ex)
    int MyFuncOne(int num=7)
    {
        return num + 1;
    }
    void main(){
        MyFuncOne();
        MyFuncOne(7);
    }

    인자를 전달하지 않으면 매개변수 디폴트값에 의해 초기값이 정해지게 됩니다. 그래서 위 코드에서 MyFuncOne();MyFuncOne(7); 은 그 결과가 같습니다.

  • 선언 위치

    디폴트 값은 함수의 선언위치에서만 선언할 수 있습니다. 컴파일러는 함수의 디폴트 값 지정여부를 알아야 적절히 컴파일이 가능하기 때문입니다.

    ex)
    int MyFuncOne(int num=7);
    
    void main(){
        MyFuncOne();
        MyFuncOne(7);
    }
    
    int MyFuncOne(int num)
    {
        return num + 1;
    }
  • 부분적 default 값

    매개변수의 일부에만 디폴트 값을 설정하는것도 가능합니다.

    ex)
    int YourFunc(int num1, int num2 = 5,int num3 = 7) { ' ' ' }
    
    YourFunc(10);		//YourFunc(10, 5, 7);
    YourFunc(10,20)		//YourFunc(10, 20 7);

    단, 전달되는 인자는 왼쪽부터 채워지기 때문에, 오른쪽이 빈 상태로 왼쪽의 매개변수에만 일부 채워진 디폴트 값은 의미를 갖지 못합니다.


Namespace

  • namespace 의 필요성

    예를 들어, 개발자 A와 B가 게임을 만든다고 생각해봅시다. 그런데 서로 개발 도중에 전역변수로
    HP 변수를 만들었다고 해봅시다. 그러면 서로의 프로그램에서는 동작에 문제가 없겠지만 추후에
    코드를 합치게 된다면 이름의 중복으로 문제가 발생하게 됩니다. 이때 사용할 수 있는 기술이 namespace 입니다. 그래서 네임스페이스를 사용하면 그러한 중복 오류를 피하면서 같은 이름을 사용할 수 있습니다. 그리고 네임스페이스 공간 안쪽에는 함수가 있어도 됩니다.

  • namespace 문법

    namespace 이름1 {
        int HP = 100;
    }
    
    namespace 이름2 {
        int HP = 100;
    }
    
    void main(){
        이름1::HP = 20; // 이름1 네임스페이스 공간에 접근
        이름2::HP = 30; // 이름2 네임스페이스 공간에 접근
    }
  • using

    네임스페이스를 사용할 때, :: 연산자를 활용하여 공간에 접근해야 합니다. 근데 이게 여간 귀찮은게 아니죠. 그래서 사용할 수 있는 문법이 using 입니다. 다음과 같이 사용 가능합니다.

    using namespace std;
    
    void main(){
        cout << "Hello World" << endl;
    }

새로운 자료형 true,false

C언어 에서는 논리값을 구성할 때, 1과 0을 통해 참과 거짓을 판별했습니다. C++ 에서는 이 부분이 참과 거짓을 판별하기에는 불명확하다고 생각해서, 새로운 자료형인 bool 을 도입했습니다. bool 의 값으로는 두 가지, truefalse 만 가능하며, 각각 C언어에서 1과 0을 의미합니다.


참조자 Reference

	int d = 20;
	int& r = d; // 참조자
    int& k = d; // 여러개 생성도 가능

Heap 메모리 사용 키워드

malloc() ---->  new
free()   ---->  delete
void main(){
    int* p = new int; // 4바이트의 공간을 생성하고, 포인터 변수 p로 가르켜줘! 
    
    delete(p);
}


헤더 문서 .h

.h 가 붙은 헤더문서들은 C++ 를 만들면서 새롭게 개편되었고, 그 이름이 .h가 빠지고 앞쪽에 c 가 붙었습니다. 완전히 새롭게 만들어 진것들은 .h 만 빠졌습니다. 이 부분은 알아만 둡시다.



C++ struct 와 class



C의 struct 와 C++의 struct

  • C의 struct

    #include <stdio.h>
    
    struct Student {
        //멤버 변수
        char* name;
        int kor;
        int eng;
        double aver;
    };
    
    void output(Student stu);
    
    void main() {
        struct Student stu;
        stu.name = "sam";
        stu.kor = 80;
        stu.eng = 100;
        stu.aver = (stu.kor + stu.eng) / 2.0;
        output(stu);
    
        struct Student stu2;
        stu2.name = "robin";
        stu2.kor = 90;
        stu2.eng = 95;
        stu2.aver = (stu2.kor + stu2.eng) / 2.0;
        output(stu2);
    }
    
    // 학생의 정보를 출력해주는 코드를 다시 쓰려니 짜증이 난다-> 함수로 만들자.
    void output(Student stu) {
        printf("name : %s",stu.name);
        printf("kor : %d",stu.kor);
        printf("eng : %d",stu.eng);
        printf("aver : %.2lf",stu.aver);
    }

    C에서는 위 코드와 같이 구조체를 만들었습니다. 구조체 안에는 멤버변수만 선언할 수 있었고, struct Student 자료형을 통해 구조체 변수를 만들어 멤버변수에 접근할 수 있었습니다. 또한 출력문의 반복이 귀찮아 함수를 통해 출력문 반복을 간편하게 만들어 주었습니다. 다만, 이는 절차지향 적인 프로그래밍 방식이며, 객체지향적인 프로그래밍에서는 이와 같은 방식은 선호하지 않았습니다.

  • C++ 의 struct

    #include <iostream>
    using namespace std;
    
    struct Student {
        //멤버 변수
        const char* name;
        int kor;
        int eng;
        double aver;
    
        //멤버변수 값을 출력하는 기능(Function) 을 정의 
        void output() {
            cout << "name : " << name << endl;
            cout << "kor : " << kor << endl;
            cout << "eng : " << eng << endl;
            cout << "aver : " << aver << endl;
            cout << endl;
        }
    };
    void main() {
        Student stu;
        stu.name = "sam";
        stu.kor = 80;
        stu.eng = 100;
        stu.aver = (stu.kor + stu.eng) / 2.0;
        stu2.output();
    
        Student stu2;
        stu2.name = "robin";
        stu2.kor = 90;
        stu2.eng = 95;
        stu2.aver = (stu2.kor + stu2.eng) / 2.0;
        stu2.output();
    }

    C에서는 구조체 안에 변수만 정의가 가능했습니다. 하지만 C++에서는 변수 뿐 아니라 함수까지 정의할 수 있었습니다. 그런데 여기서 우리에게 이상한 점이 생겼습니다. 분명 C에서는 구조체 변수 를 선언한다고 이야기합니다. 그런데 구조체 안에 변수 뿐 아니라 함수까지 정의할 수 있는 마당에 구조체 변수라는 말은 썩 어울리지 않는것 같습니다. 그래서 C++ 를 만들때, 구조체 변수가 아닌 Object, 의역하자면 객체라고 부르기로 했습니다. 즉, 우리가 만든 struct Student 는 멤버 변수와 함수를 정의한 하나의 객체라고 보자는 이야깁니다. 이렇게 정의를 하니, 우리는 출력에 관한 함수를 따로 만들필요 없이 언제 함수가 사용되는지, 누가 함수를 사용하는지만 알면 됩니다. 여기가 객체지향의 시작점 입니다.

C++ 의 Class

C++ 이 만들어질 때, 구조체 안에 함수를 넣고 구조체 자체에서 변수와 기능들이 한꺼번에 들어가 있으면 좀 더 편할것 같다는 아이디어가 나오게 됩니다. 그래서 변수와 함수를 모두 구조체에 넣고 변수만 있는 구조체는 구조체 변수로, 변수와 함수 모두 있는 구조체는 구조체 객체로 사용을 하다보니 개발자들이 너무 헷갈린다는 이야기가 나오게 됩니다. 그래서 C++ 에서는 구조체 객체라는 개념을 새로운 개념 Class 로 만들게 됩니다.

  • Class 생성

    클래스는 구조체와 그 구조가 비슷합니다. 클래스에는 다음과 같이 멤버변수가 있고, 멤버 함수가 있습니다.

    class Person {
        //멤버 변수
        const char* name;
        int age;
    
    public:
    
        //멤버변수에 값을 입력해주는 기능 - 멤버함수 
        void init(const char* name, int age) {
            //멤버변수에 전달받은 매개변수 값을 대입해주는 기능 
            //class 안에서 객체 본인을 지칭하는 특별한 키워드 this
            (*this).name = name;
            this->age = age;
        }
        //멤버값 출력기능 - 멤버함수
        void show() {
            cout << "name : " << name << endl;
            cout << "age : " << age << endl;
            cout << endl;
        }
    };
    
    void main() {
        // 구조체 변수 X -> 변수 + 함수 -> Object(객체) Heap 메모리 생성
    
        Person* person = new Person;
        //(*person).init("sam", 20); // person->init() 편하게 표현하기 위해! 
        person->show();
    
    }

    Person 이라는 이름의 클래스를 만들었고, 멤버 변수로는 const char* nameint age , 멤버 함수로는 void init(, , ,),void show() 를 만들었습니다. 그리고 new 연산자를 이용하여 메모리에 Person 크기 만큼의 메모리공간을 만들어주었습니다. 그 메모리를 Person 포인터 변수 person 에 할당해주었으며, 포인터 변수를 통해 Person 클래스의 멤버 함수에 접근할 수 있게 됩니다.

  • 접근제한자

    위 코드에 있는 public 키워드는 함수와 변수의 접근제한자 입니다. 변수와 함수를 클래스 내부가 아닌 다른곳에서 무분별하게 사용하다가는 오류가 날 가능성이 굉장히 높아지기 때문에 각각의 정보은닉이 필요합니다. 그래서 접근제한자 public,private,protected 를 이용하여 각각의 접근방식을 제한하게 됩니다. 그래서 포인터 변수를 이용하면 public 접근제한자가 걸려있는 멤버 함수에만 접근이 가능하며, 아무 접근제한자도 지정하지 않으면 private 로 걸리기 때문에 멤버 변수에는 접근이 불가합니다.

  • 생성자 함수와 this

    자, 그래서 포인터 변수를 통해 init 함수를 호출하여 각각의 멤버변수들의 값을 넣어주었고, show() 함수를 통해 출력해주었습니다. 그런데 여기서 또 한번 불편함이 느껴집니다. 만일, 클래스를 생성함과 동시에 멤버변수들을 초기화할 수는 없을까하는 의문점입니다. 그래서 C++ 에서는 클래스 생성과 동시에 멤버변수들을 초기화 할 수 있는 생성자 함수를 만들어주었습니다. 생성자함수는 객체가 생성되면 자동으로 실행되는 특별한 함수를 말합니다. 생성자 함수를 만드는 규칙은 다음과 같습니다.
    1) 함수이름은 Class 이름과 같아야 합니다.
    2) 리턴값을 명시하지 않아야 합니다.

    ex)
    Person(const char* name,int age){
        this->name = name;
        this->age = age;
    }
    
    Person* person = new Person("sam",20); //객체 생성시 초기화 가능!

    이렇게 해서 생성자 함수를 만들었습니다. 그런데 특이한 키워드가 하나 보입니다. 바로 this 입니다. 보통의 개발자들은 이름을 지을 때 명확하게 짓기를 원합니다. 그런데 이렇게 이름을 짓다보니 중복을 피하기는 어려웠습니다. 위 예시도 마찬가지로, 멤버변수의 이름과 생성자 함수의 매개변수 이름이 동일하다 보니 중복이 일어납니다. 이를 방지하기 위해 this 키워드를 사용하여 class 안에서 객체 본인을 지칭하는 특별한 키워드를 만들었습니다. 그래서 위 코드와 같이 사용하면 이름의 중복을 피할 수 있습니다.

profile
Developer

0개의 댓글