본문 바로가기

코딩 및 기타/어서와! 자료구조와 알고리즘

C++ 문법 뽀개기

728x90

∙ C언어와 C++ 그리고 C#이 무엇인가?

- C언어 : 아주 먼 옛날 벨 연구소에서 Unix라는 운영체제(OS)를 개발 목적으로 탄생한 언어이다.

- C++ : 조금 먼 옛날 C언어에서 한단계 진화한 언어로 객체와 클래스라는 개념이 처음 도입이 되었다. 이후 템플릿이라는 기능이 추가되어 더욱더 강력해졌고 지금도 계속 꾸준히 발전중이다.

- C# : 마이크로소프트사에서 2000년대 개발한 언어인데, 사실 Java를 대항하기 위해 탄생한 언어이다 보니 C와 C++만큼 관련은 없다.

 

∙ C++ 의 장점

1. 속도가 빠르다. (python 보다 수십배에서 수백배정도!)

2. 사용자가 직접! 메모리를 관리할 수 있다.

3. cross-platform : 하나의 코드를 여기저기서 사용

-> C++으로 하나를 만들어 놓으면 안드로이드, 윈도우 등 여러 곳에서 가져올 수 가 있다.

 

 ∙ 함수

- 코드 뭉치로 자주 사용할 것 같은 코드를 한 군데 모아, 추후에도 사용하기 편하기 해주는 아주 좋은 기능이다.

- 자주 사용할 것 같은 코드를 하나의 함수로 모은다

> 똑같은 코드를 사용해야 할 때에는 작성한 함수를 사용한다.

> 작성하는 코드의 양이 줄어든다.

> 적은 코드로 많은 기능을 만들 수 있다.

따라서 함수를 작성하실 땐, 반복되는 코드의 재사용에 대해 생각해보는게 매우 중요하다.

#include <iostream>

using namespace std; 

void sayHello(); // 함수 선언 


int main()
{
	cout << "main" << endl;
    sayHello(); // 함수 호출
}

// 함수 작성
void sayHello()
{
	cout << "Welcome" << endl;
}

 

- 함수 오버로딩 (Overloading)

> 함수 오버로딩은 같은 이름의 함수가 있어도 매개변수를 보고 c++이 알아서 찾아준다.

> 함수 오버로딩이 적용되기 위해서 아래조건이 중요

    1. 함수 이름이 같아야한다.

    2. 매개변수의 수가 다르거나, 자료형이 달라야한다.

    3. 반환형의 차이는 함수 오버로딩에 적용이 안된다.

#include <iostream>

using namespace std;

// 인자의 개수를 통해 구별을 함 
int add(int a, int b);
int add(int a, int b, int c);

int main()
{
	cout << add(1,2) << endl;
    cout << add(1, 2, 3) << endl;
}

int add(int a, int b)
{
	cout << "addTwo" << endl;
    return a + b;
}

int add(int a, int b, int c)
{
	cout << "addThree" << endl;
    return a + b + c;
}

 

포인터와 참조

∙ 포인터

- 포인터란 우리가 사용하는 변수가 실제로 담기는 주소를 의미한다.

- 우리가 만드는 변수는 분명 컴퓨터 어딘가 잘 보관이 될 테고, C++에서 우리는 그 주소를 확인해 볼 수 있다.

 #include <iostream>
 
 using namespace std;
 
 int main()
 {
 	int water = 10;
    
    //  * : 포인트 변수를 선언, & : 변수의 주소를 가져와라
    int *p_water = &water;
    
    cout << "water" << water << endl;
    // p_water 주소에 들어 있는 값 출력
    cout << "p_water" << *p_water << endl;
    
    // water 주소 값 출력 (두개의 주소는 같다)
    cout << "water location" << &water << endl;
    cout << "p_water location" << p_water << endl;
    
    // 10이 아닌 11이 나온다 -> 주소가 같기 때문에
    *p_water = *p_water + 1;
    cout << "Now count" << water << endl;
 }

- call by value, call by reference

> main함수에서 사용한 변수를 참조하기 때문에 main에서 사용하던 변수의 값에 영향을 준다는게 중요하다.

 

 

cf)

 - string 함수

int main()
{
	string sparta = "Sparta";
    string coding = "Coding";
    string club = "Club";
    
    // 문자열 합치기
	string result = sparta + coding + club;
    cout << result << endl;
    
    // 문자열 길이 구하기
    cout << result.size() << endl;
    
    // 문자열 나누기
    // 출력 결과 : CodingClub
    cout << result.substr(sparta.size(), result.size()) << endl;
    
    // 문자열 찾기
    // 인덱스 위치 출력됨
    cout << result.find(club) << endl;
    
}

 

∙ 구조체 

- 다양한 자료형을 한데 묶어서 하나로 관리하고 싶을 때 C++에서는 이를 구조체를 사용하여 해결한다.

- struct 라는 키워드를 사용한다.

// struct.cpp
#include <iostream>

using namespace std;

struct Person
{
    string name;
    int age;
};

int main()
{
    Person p1;
    p1.name = "John Doe";
    p1.age = 20;

    Person p2 = {"Jane", 30};

    cout << p1.name << endl;
    cout << p2.name << endl;

    return 0;
}

 

 

∙ 클래스와 객체

- C++에서 클래스는 중요한 의미를 가지고 있다. 가장 큰 역할을 하지만 지금은 클래스 외에도 많은 기능이 확장되어 더욱 편리하게 사용할 수 있다.

- 클래스(Class), 객체(Object), 인스턴스(Instance), 메소드(Method)

> 클래스 (Class)

과자 모형이다. 내가 원하는 모양의 과자를 만들기 위해 기본 틀을 제작하는거다.

> 객체 (Object)

과자 모형을 통해 실제로 만들어진 과자를 의미한다.

> 인스턴스 (Instance)

클래스의 인스턴스를 객체라 한다. 객체와 인스턴스는 같은 의미라고 생각하는게 좋다

> 메소드 (Method)

클래스에서 제공하는 기능이고, 함수와 생김새는 같다. 주로 멤버변수를 활용하는 메소드를 가지고 있다.

// class.cpp
#include <iostream>

using namespace std;

class Person
{
// 외부에서 접근할 수 없음
private:
	int age;

// public으로 지정을 안해주면 기본적으로 private으로 설정됨
public:
    string m_name;
    void sayHello()
    {
        cout << "Hello" << endl;
    }
};

int main()
{
    Person p1;
    p1.m_name = "Eric Clapton";

	/*
	//private에 있기 때문에 age에 접근이 불가능
    p1.age = 10;  
    */

    cout << p1.m_name << endl;
    p1.sayHello();

    return 0;
}

 

∙ 생성자와 소멸자

∙ 생성자

- 클래스가 생성될 때 딱 한번 실행되는 메소드이다.

- C++에서 생성자는 클래스와 같은 이름으로 선언해준다.

- 다른 메소드와는 다르게 반환 타입이 없다

// constructor.cpp
#include <iostream>

using namespace std;

class Person
{
public:
    string m_name;

    Person(string name) // 생성자... 함수랑 똑같다고 생각하면됨
    {
        cout << "Constructing Person......" << endl;
        m_name = name;
    }
    void sayHello()
    {
        cout << "Hello I'm " << m_name << endl;
    }
};

int main()
{
    Person *p1 = new Person("Eric Clapton");
    // Person p1 = Person("Eric Clapton");
    // Person p1("Eric Clapton");

    p1->sayHello();

    return 0;
}

 

∙ 소멸자

- 클래스가 소멸될 때 실행되는 메소드이다.

- 소멸자는 클래스 이름 앞에 ~를 붙여서 선언해준다.

- 반환형과 인자가 없다는게 특징이다.

- new로 선안한 객체는 반드시 delete를 통해 소멸시켜줘야한다.

// destructor.cpp
#include <iostream>

using namespace std;

class Person
{
public:
    string m_name;

    Person(string name)
    {
        cout << "Constructing Person..." << endl;
        m_name = name;
    }

	// 소멸자
    ~Person()
    {
        cout << "Destructing Person..." << endl;
    }
    void sayHello()
    {
        cout << "Hello I'm " << m_name << endl;
    }
};

int main()
{
    Person *p1 = new Person("Eric Clapton");
    // Person p1 = Person("Eric Clapton");
    // Person p1("Eric Clapton");

    p1->sayHello();
	 // 이 타이밍에 소멸자를 호출한다.
    delete p1;

    // cout << "Good bye " << endl;
    return 0;
}

 

∙ 상속

- 자식이 부모로부터 물려받는 것을 상속이라고 하고, 자식은 부모와 여러가지로 비슷한 점을 많이 가지고 있지만, 완전하게 똑같지는 않다.

- C++에서는 상속을 이용해서 이전에 만든 클래스를 기반으로 비슷하면 서로 다른 클래스를 만들 수 있다.

// inheritance.cpp
#include <iostream>

using namespace std;

class Person
{
private:
    string m_name;

public:
    Person(string name)
    {
        cout << "Construting Person..." << endl;
        m_name = name;
    }
    ~Person()
    {
        cout << "Destructing Person..." << endl;
    }

    void sayHello()
    {
        cout << "Hello I'm " << m_name << endl;
    }
    string getName()
    {
        return m_name;
    }
};

// 상속을 받겠다
class Musician : public Person
{
private:
    string m_instrument;

public:
    Musician(string m_name) : Person(m_name)
    {
        cout << "Constructing Musician..." << endl;
    }
    ~Musician()
    {
        cout << "Destructing Musician..." << endl;
    }
    void setInstrument(string instrument)
    {
        m_instrument = instrument;
    }
    string getInstrument()
    {
        return m_instrument;
    }
};

int main()
{
    Musician m1 = Musician("Eric Clapton");
    m1.setInstrument("guitar");
    m1.sayHello();
    cout << m1.getInstrument() << endl;

    return 0;
}

 

- is-a 관계

> 상속 관계 (is a relationship : inheritance)를 의미한다.

> 뮤지션과 사람의 관계를 is-a관계라 말하며, 이는 상속의 가장 대표적인 관계이다.

> 뮤지선을 파생 클래스, 사람을 기본 클래스라고 한다.

 

 

∙ 함수 오버라이딩

- 함수 오버로딩 : 클래스 내에 이름이 동일한 함수가 여러 개 존재

- 함수 오버라이딩 : 부모 클래스에 이미 정의된 함수를 재정의해서 사용

// overriding.cpp
#include <iostream>

using namespace std;

class Person
{
// protected 선언을 하면 자식한테 넘겨줄수 있지만, 외부에서는 불가능하다
protected:
    string m_name;

public:
    Person(string name)
    {
        m_name = name;
    }

    void sayHello()
    {
        cout << "Hello I'm " << m_name << endl;
    }
};

class Musician : public Person
{
private:
    string m_instrument;

public:
    Musician(string m_name) : Person(m_name) {}
	// 함수 오버 라이딩
    void sayHello()
    {
        cout << "Hi I'm " << m_name << endl;
        cout << "I play the " << m_instrument << endl;
    }
	// 위와 같은 함수이지만 인자가 다르기 때문에 오버 로딩이라고한다.
    void sayHello(string lang)
    {
        if (lang == "ENG")
        {
            cout << "Hello!" << endl;
        }
        else
        {
            cout << "I can only speak in English..." << endl;
        }
    }

    void setInstrument(string instrument)
    {
        m_instrument = instrument;
    }
};

int main()
{
    Musician m1 = Musician("Eric Clapton");
    m1.setInstrument("guitar");
    m1.sayHello();
    m1.sayHello("KOR");
    // cout << m1.m_name << endl;

    return 0;
}

 

∙가사함수

// virtual.cpp
#include <iostream>

using namespace std;

class Person
{
protected:
    string m_name;

public:
    Person(string name)
    {
        m_name = name;
    }

    virtual sayHello()
    {
        cout << "Hello I'm " << m_name << endl;
    }
};

class Musician : public Person
{
public:
    Musician(string m_name) : Person(m_name)
    {
    }
    void sayHello()
    {
        cout << "Hi I'm " << m_name << endl;
        cout << "I'm a musician!" << endl;
    }

    void playSomething()
    {
        cout << "lalala~" << endl;
    }
};

class Baker : public Person
{
public:
    Baker(string m_name) : Person(m_name)
    {
    }
    void sayHello()
    {
        cout << "Hi I'm " << m_name << endl;
        cout << "I like bread!" << endl;
    }
};

int main()
{
	// vrtual로 person 클래스가 안되어 있으면 Person sayHello ㅎ마수가 실행이 된다
    
    Person *p1 = new Musician("Jeff");
    p1->sayHello();
    // p1->playSomething();
    cout << endl;

    Person *p2 = new Person("Jane");
    p2->sayHello();
    cout << endl;

    p1 = new Baker("Yumi");
    p1->sayHello();

    delete p1;
    delete p2;

    return 0;
}

 

∙ 템플릿

- C++의 여러가지 특징 중 하나로, 일반화 프로그래밍이란 특징이 있다. 이전까지 배운 객체지향 프로그래밍(OOP)과는 전혀 다른 프로그래밍 기법이다.

- 일반화 프로그래밍에서는 데이터의 타입과 관련없는 코드를 작성하는 것인데, 이를 위해서 템플릿이 필요하다.

 

∙ 함수 템플릿

- 두 개의 숫자를 더해주는 함수를 만들 때, 원래는 자료형 별로 함수를 만들어줘야 한다. 하지만 템플릿을 사용하면 하나의 함수로 쉽게 구현이 가능하다.

// functiontemplate.cpp
#include <iostream>

using namespace std;

int sum(int a, int b)
{
    return a + b;
}

double sum(double a, double b)
{
    return a + b;
}

// 템플릿 생성
template <typename T>
T sum(T a, T b)
{
    return a + b;
}

int main()
{
    int s1 = sum(1, 2);
    double s2 = sum(2.2, 2.0);
    
    // 템플릿 함수 호출 <string> 형이라고 템플릿에 알려준다.
    string s3 = sum<string>("Sparta", "CodingClub");
    double s4 = sum<double>(2.2, 2.0);

    cout << s1 << endl;
    cout << s2 << endl;
    cout << s3 << endl;
    cout << s4 << endl;

    return 0;
}

 

∙ 템플릿 특수화

- 특정 데이터 타입 한해서 따로 처리를 하고 싶을때 사용 (예외처리)

//templatespecialization.cpp
#include <iostream>

using namespace std;

template <typename T>
T sum(T a, T b)
{
    return a + b;
}

// 템플릿 예외 처리
template <>
char sum<char>(char a, char b)
{
    cout << "Unable to sum char!" << endl;
    return a;
}

int main()
{
    cout << sum<int>(1, 2) << endl;
    cout << sum<double>(2.0, 2.0) << endl;
    cout << sum<string>("Sparta", "CodingClub") << endl;

    char a = 'a';
    char b = 'b';
    cout << sum<char>(a, b) << endl;

    return 0;
}