C++

04. 클래스와 객체

til_t 2021. 1. 27. 22:34

클래스와 객체

 


 

< ex01_class.cpp >

 

#include <iostream>
#include <string>

using namespace std;


class Circle{
public:
int radius;
string color;
double calcArea(){ // 파이썬과 달리 self 매개 변수 없다
return 3.14 * radius * radius;
}
};


int main(int argc, char const *argv[])
{
Circle obj; // 객체 생성
obj.radius = 100;
obj.color = "blue";
// c++은 고정시키고 사용
// obj.area = 40; // 에러 -- 동적으로 멤버 추가 불가
cout << "area : " << obj.calcArea() << endl;

return 0;
}

 

  • c++를 사용하는 궁극적인 목표 -> 클래스를 사용하기 위함
  • 멤버 (멤버변수(데이터), 멤버함수(메서드))
  • 클래스 - 객체(인스턴스)의 형태를 정의하는 설계도
  • 객체(인스턴스) - 클래스의 형태를 취하는 실체

  • 클래스 정의

    • class 클래스 이름{ // 클래스 이름은 파스칼 표기법
    • 자료형 멤버변수;
    • // 변수도 고정시켜서 사용
    • 반환형 멤버함수(); // 메서드
    • };
  • 객체 생성

    • 클래스명 객체명; -> 스택에 만들어진다, 인스턴스는 스택에 위치한다, 정적할당, 선언과 동시에 메모리가 잡힌다 (지역변수면 스택에 만들어진다) ex) Circle obj;

    • 정적할당 -> 스택, 동적할당 -> 힙

    • 지역변수와 같이 선언한다, 함수가 끝날 때 사라진다는 것도 같다, 다른 점은 정적할당인가 동적할당인가의 차이이다

      • 파이썬의 인스턴스는 힙에 만들어진다 (c = Circle())
      • 파이썬에서 정적할당은 숫자와 bool 밖에 없다, 나머지는 동적할당으로 힙에 생긴다
  • 객체 멤버 접근 (접근 지정자에 따라 다르다)

    • . 연산자로 접근 ex) obj.radius = 3;
  • 접근 지정자

    • private (비공개), 클래스 안에서만 접근, 사용 가능
    • protected (비공개), 상속에서 사용
    • public (공개), 어디서나 접근 가능
    • 보통 멤버변수는 private, 메서드는 public으로 운영한다
  • c++에는 가비지 컬렉터가 없다! -> 힙에 있는 메모리를 지우는 일은 개발자의 책임

     

< ex03_car.cpp >

 

 

#include <iostream>
#include <string>

using namespace std;


class Car{
public:
int speed;
int gear;
string color;

void speedUp(){
speed += 10;
}

void speedDown(){
speed -= 10;
}
};

int main(int argc, char const *argv[]) {

Car myCar;
myCar.speed = 100;
myCar.gear = 3;
myCar.color = "red";
myCar.speedUp();
myCar.speedDown();

return 0;
}

 

 

< ex04_overload.cpp >

 

#include <iostream>

#include <string>

using namespace std;



class PrintData{

public:

void print(int i){ cout << i << endl;}

void print(double f){ cout << f << endl;}

void print(string s = "No Data!"){ cout << s << endl;}

// 함수 명은 같지만 매개변수가 다르다, 다 다른 함수

};



int main(int argc, char const *argv[]) {

PrintData prn;



prn.print(1);

prn.print(3.14);

prn.print("C++ is cool");

prn.print();



return 0;

}

 

  • 객체 지향의 특징

    • 캡슐화

      • 묶어서 관리한다, 관리해야 하는 데이터와 데이터를 이용한 함수가 클래스로 묶여있다
    • 정보 은닉

      • 정보를 숨기겠다, 접근제한자를 통해서 정보를 숨길 지 공개할 지 선택할 수 있다
    • 상속과 다형성

      • 부모의 내용을 자식이 받아서 사용하는 것
      • 다형성 -> 형태가 많다라는 뜻
  • 상속

    • class 자식 클래스 명: public 부모 클래스 명{
    • }
    • public이면 public으로 가져오겠다, private라면 부모클래스에 있는 모든 접근제한자가 private로 바뀌어서 상속받는다

 

< ex05_inherit.cpp > 

 

#include <iostream>

using namespace std;



class Shape{

protected:

// private로 했을 땐, x, y는 상속되지 않았을 것

// 외부에는 공개하지 않으면서 상속은 되게 하는 것이 protected의 역할

int x, y;

public:

void draw(){}

void move(){}

};



class Rectangle: public Shape{

protected:

int width, height;

public:

int calcArea(){

return width * height;

}

};

 

  • 헤더와 cpp파일을 구분하지 않고 하나의 파일에 다 넣으면 관리하기가 힘들어진다
  • class 하나당 파일을 하나로 정의한다
  • 클래스 원형과 구현 정의 분리

    • 헤더 파일에 클래스 원형

      • 멤버 변수 정의
      • 멤버 함수의 원형 정의
    • cpp 파일에 멤버 함수 정의

      • 헤더 파일을 먼저 include
  • c++에서는 변수와 함수 중복시 듀플리케이트 에러가 난다
  • 중복되는 것을 피하기 위해서 함수 원형을 헤더에 남기고 실제 함수 정의 코드는 정의파일에 남긴다
  1. easy c++ projects 확장팩 설치
  2. 디렉토리 새로 오픈
  3. F1 -> create new c++ project -> linux
  4. F1 -> create new class constructor
  5. 컴파일하고 싶으면 터미널에 make
  6. 실행하고 싶다면 터미널에 bin/main.exe

 

< include/Car.hpp >

 

#pragma once
#include <string>
using namespace std;
// 헤더 파일

// 클래스 원형
class Car {
// 디폴트 접근 제한자 : private
int speed;
int gear;
string color;
public:
int getSpeed(); // 함수 원형
void setSpeed(int s);
};

 

< include/PrintData.hpp >

 

#pragma once

#include <string>

using namespace std;



class PrintData{

public:

void print(int i);

void print(double f);

void print(string s = "No Data!"); // 초기값 배정 (헤더파일에서만 해주면 된다)

};

 

 

< src/Car.cpp > 

 

#include "Car.hpp" // "" 검색 순서 : cwd(와 include 검색) -> 사용자 lib -> 컴파일러 lib
#include <iostream> // <> 검색 순서 : 사용자 lib -> 컴파일러 lib

// 메서드임을 나타내기 위해 :: 스코프 연산자 쓴다, 어디 소속인지
void Car::setSpeed(int s){
speed = s;
// 지역변수 speed X, 멤버변수 speed
}

int Car::getSpeed(){
return speed;
}

 

 

< src/PrintData.cpp>

 

#include "PrintData.hpp"
#include <iostream>

void PrintData::print(int i){
cout << i << endl;
}

void PrintData::print(double f){
cout << f << endl;
}

void PrintData::print(string s){ // 디폴트 값 지정은 헤더파일에서만 지정
cout << s << endl;
}

 

 

< src/main.cpp > 

 

#include <iostream>
#include <string>
#include "Car.hpp"
#include "PrintData.hpp"
using namespace std;

void printCar(Car car){
cout << car.getSpeed() << endl;
car.setSpeed(20);
}

int main(int argc, char const *argv[])
{
Car myCar;
myCar.setSpeed(100);
printCar(myCar); // call by value
cout << "speed : " << myCar.getSpeed() << endl;

PrintData pd;
pd.print(10);
pd.print(10.2);
pd.print("Hello World");
pd.print();

return 0;
}

 

< Makefile >

 

CXX := g++
CXX_FLAGS := -Wall -Wextra -std=c++17 -ggdb

BIN := bin
SRC := src
INCLUDE := include
LIB := lib

LIBRARIES :=
EXECUTABLE := main

all: $(BIN)/$(EXECUTABLE)
run: clean all
cls
./$(BIN)/$(EXECUTABLE)
$(BIN)/$(EXECUTABLE): $(SRC)/*.cpp
$(CXX) $(CXX_FLAGS) -I$(INCLUDE) -L$(LIB) $^ -o $@ $(LIBRARIES)

clean:
-del $(BIN)\*