[C++] 열혈 프로그래밍

Joonseo·2023년 10월 21일

1.1 클래스(Class)와 정보은닉

  • 어떠한 프로그램 개발을 위해 C++과 같은 객체지향언어로 코드를 작성하는 경우 가장 중요한 부분 중 하나는 보안성 이라고 할 수 있다.
    이를 고려하지 않고 코드를 작성하고 프로그램을 개발하면 해당 프로그램에
    저장되는 정보들이 무분별하게 악용될 수 있기 때문이다.
  • 지금 당장은 프로그램 개발을 하는 것은 아니니 와닿지 않을 수 있다. 하지만 실무나 프로젝트를 진행하다보면 보안성의 중요함을 느낄 수 있을 것이다.

1.2 정보은닉의 구현

  • 그렇다면 어떻게 정보가 쉽게 유출되지 않게 보호할 수 있을까?
    이해를 돕기 위해 정보유출에 취약한 사례를 보도록 하자

< 맴버변수가 public 키워드로 정의되어있는경우 >

#include <iostream>
using namespace std;

class Student{
public:
    char *name;
    int age;
};

int main(void){
    Student s1;
    s1.name = "kim";
    s1.age = 10;

    cout<<s1.name<<endl;
    cout<<s1.age<<endl;

    return 0;
}

➡️ 이러한 경우, 어디서든 name 이나 age 같은 데이터에 접근할 수 있게 된다. 데이터의 노출뿐만 아니라 조작까지 가능하므로 보안에 굉장히 취약하다.

class Student{
private:
    char *name;
    int age;
public:
    void getName() const{
        cout<<name<<endl;
    }
    void getAge() const{
        cout<<age<<endl;
    }
};

Student 클래스의 맴버변수들을 private 키워드로 제한했다. 이러면 main 함수에서의 호출이 제한된다. 하지만 때에 따라서 맴버변수를 호출해야되는 경우가 있지 않나? 그래서 public 스페이스에 getName()getAge() 함수를 선언해 맴버변수에 접근할 수 있도록 하였다.

📢그런데 기존에 보던 함수랑 조금 다른 점이 있다. 바로 const 키워드이다. private 스페이스에 선언된 맴버변수에 저장된 값을 변경하지 않겠다 를 명시한다.

  • private 필드에 선언함으로써 정보를 보호하고 필요한 경우 public필드에 정의된 const 함수로 해당 맴버에 접근할 수 있다.

1.3 생성자(Constructor)

  • 지금까지( 생성자가 없는 경우 ) 객체( Class )를 초기화할 때 아래와 같은 방법을 사용했다.
class TwoNumb{
private:
    int x;
    int y;
public:
    void initNum(int a, int b){
        x = a, y = b;
    }
    void printNum()const{
        cout<<"x: "<<x<<" y: "<<y<<endl;
    }
};

int main(void){
    TwoNumb ab;
    ab.initNum(1, 3);
    ab.printNum();

    return 0;
}
  • main에서 객체를 생성하고 이를 초기화 해줄 함수 init___를 호출해 초기화하였다. 이러한 번거로움을 피하기 위해 생성자 함수를 정의하여 객체를 생성하는 동시에 초기화까지 해보자.
class TwoNumb{
private:
    int x;
    int y;
public:
    TwoNumb(int a, int b){
        x = a, y = b;
    }
    void printNum()const{
        cout<<"x: "<<x<<" y: "<<y<<endl;
    }
};

int main(void){
    TwoNumb ab(1,3);
    ab.printNum();

    return 0;
}

➡️ 이렇게 선언과 동시에 객체를 초기화할 수 있게 되었다. 생성자의 특징 몇가지를 살펴보자.

1.3.1 생성자(Constructor)의 오버로딩

  • 생성자반환형 은 없지만 엄연한 함수이므로 오버로딩이 가능하다.
    TwoNumb(int a, int b){
        x = a, y = b;
    }
    TwoNumb(int a){
        x = a;
        y = 0;
    }
    TwoNumb(){
        x = 0;
        y = 0;
    }

1.3.2 생성자(Constructor)와 이니셜라이저

  • 이니셜라이저(Initializer) 란 생성자가 호출되는 동시에 맴버변수를 초기화할 수 있는 키워드이다. 생성자 함수 내부에서 초기화하는 방식보다 속도가 빠르다!
    TwoNumb(int a, int b)
        : x(a), y(b) 
    {
    }
  • 이니셜라이저를 활용하여 클래스로 생성된 맴버변수도 초기화할 수 있다.
class Point{
private:
    int xpos;
    int ypos;
public:
    Point(int x, int y)
        :xpos(x), ypos(y)
    {  
    }
};

class Straight{
private:
    Point posOne;
    Point posTwo;
public:
    Straight(const int &x1, const int &y1, const int &x2, const int &y2)
        :posOne(x1, y1), posTwo(x2,y2)
    {
    } 
};
  • 이전 Fruitsale.cpp 예제에서 const 변수는 생성자함수나 다른 함수를 통해 초기화할 수 없었다. 하지만 이니셜라이저를 사용하면 가능하다!
class Point{
private:
    int xpos;
    int ypos;
public:
    Point(int x, int y)
        :xpos(x), ypos(y)
    {  
    }
};

class Straight{
private:
    const int posz;
    Point posOne;
    Point posTwo;
public:
    Straight(const int &x1, const int &y1, const int &x2, const int &y2, int a = 0)
        :posOne(x1, y1), posTwo(x2,y2), posz(a)
    {
    } 
};

📢생성자 함수 선언부에 보면 int a = 0 으로 선언된 매개변수가 있다.
특정 arguments가 전달되지 않았을 때를 보완하기 위한 default값 지정이다. main 함수에서 int a 에 대한 arguments를 전달하지 않아도 생성자 함수에서 자동으로 0 으로 초기화가 가능하다.

2.1 this 키워드의 사용

  • 쉽게 말해서 this 키워드는 객체 자신을 가르킨다.
    this 키워드의 쓰임을 몇가지 살펴보자
#include <iostream>
using namespace std;

class Point{
private:
    int xpos;
    int ypos;
public:
    Point(int xpos, int ypos){
        this->xpos = xpos;
        this->ypos = ypos;
    }
    void printPos() const{
        cout<<"xpos: "<<this->xpos<<" ypos: "<<this->ypos<<endl;
    }
};

int main(void){
    Point p1(10, 50);
    p1.printPos();

    return 0;
}

👉 line 9 의 생성자 함수 처럼 매개변수 명과 arguments의 이름이 같을 때 이를 구분하기 위해 this 키워드를 사용할 수 있다.
👉 생성자 함수 부분을 해석해보자면 this(Point 객체)의 맴버변수 xpos에 arguments 로 전달받은 값을 대입하라 정도로 할 수 있을 것이다.

#include <iostream>
using namespace std;

class Whiteboard{
private:
    int number;
public:
    Whiteboard(int x)
        :number(x)
    {}
    Whiteboard& Adder(int x){
        number += x;
        return *this;
    }
    Whiteboard& showboard(){
        cout<<"number: "<<number<<endl;
        return *this;
    }
};

int main(void){
    Whiteboard wb(0);
    wb.Adder(1).showboard().Adder(50).showboard();

    return 0;
}

👉 main 함수 내부 코드를 보면
1. Whiteboard 클래스 객체 wb 를 생성
2. wb 객체의 함수(반환형이 Whiteboard의 주소인) Adder 실행
3. 반환형이 객체의 주소값이므로 '.(dot)' 연산자를 사용해 wb에 접근

끗ㅋ

profile
🧑🏻‍💻

0개의 댓글