연산자 오버로딩이란?

C++에서 연산자가 하는 일을 함수로 개인의 필요에 맞게 구현한 것이다.

예를 들어, 클래스의 성격에 따라 필요한 연산 기능이 있다면 그에 맞게 동작하도록 기본 연산자의 기능을 재정의할 필요가 있다.

이것을 연산자 오버로딩이라 한다.

 

연산자 오버로드에 대한 일반 규칙

  • **과 같은 새로운 연자라를 정의할 수는 없다.
  • 기본 제공 데이터 형식에 적용할 때 연산자의 의미를 다시 정의 할 수 없다.
  • 오버로드 된 연산자는 비정적(non-static) 클래스 멤버 함수거나 전역 함수이어야 한다.
    (private 또는 protected 접근자의 전역 함수는 해당 클래스의 friend로 선언해야 한다.)
  • 단항 연산자 또는 이항 연산자(&, *, +, -)로 오버로드 가능하며 각 사용을 별도로 오버로드 할 수 있다.
  • 멤버 함수로 오버로드 된 연산자의 첫번째 파라미터는 항상 연산자가 호출되는 객체의 클래스 형식이다.
    (첫번째 파라미터에 대한 변환은 제공되지 않는다.)

오버로딩이 불가능한 연산자

연산자 이름
. 멤버선택
.* 멤버 포인터 선택
:: 범위
?: 조건
# 문자열 전처리기 변환
## 전처리기 연결

 

간단한 예

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
using namespace std;
 
class Point {
private :
    int x, y;
 
public :
    Point(int x_, int y_) {
        x = x_;
        y = y_;
    }
 
    void print() {
        cout << "x : " << x << ", y : " << y << "\n";
    }
};
 
 
int main(void) {
    Point p1 = { 11 };
    Point p2(22);
    
    Point p3 = p1 + p2;  // 문제가 되는 라인
 
    p3.print();
 
    return 0;
}
cs

24 라인에서 사용한 Point 객체 p3에 p1과 p2를 더한값을 저장하려고 하는 문장을 실행하면 에러가 발생한다.
왜냐하면 + 연산자에 대해 Point 객체의 덧셈은 지원해주지 않기 때문이다.

 


이를 해결하기 위해 C++에서는 연산자 오버로딩을 제공한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
using namespace std;
 
class Point {
private :
    int x, y;
 
public :
    Point(int x_, int y_) {
        x = x_;
        y = y_;
    }
 
    void print() {
        cout << "x : " << x << ", y : " << y << "\n";
    }
 
    //새로 생긴 함수
    Point operator + (Point& p) {
        x = x + p.x;
        y = y + p.y;
        return Point(x, y);
    }
};
 
 
int main(void) {
    Point p1 = { 11 };
    Point p2(22);
    
    Point p3 = p1 + p2;
 
    p3.print();
 
    return 0;
}
 
cs

새로운 함수로 operator +가 생성되었다.

+연산자에 대한 오버로딩 함수로, 반환형은 Point 객체이다.

함수명을 operator로 사용함으로써 컴파일러에게 연산자 오버로드 함수인 것을 명시한다.

 

이 함수는 31번째 라인에서 "Point p3 = p1 + p2;" 명령문으로 작동한다.

 

//출력결과

x : 3, y : 3

 

출처: https://yeolco.tistory.com/119

'C++' 카테고리의 다른 글

객체와 friend 함수  (0) 2019.11.27
생성자와 소멸자  (0) 2019.11.27
메모리 구조와 동적 메모리 할당  (0) 2019.11.27
C++이란?  (0) 2019.11.27

this 포인터

객체 자신을 가리키는 용도로 사용되는 포인터

어떤 객체에 의해 멤버함수가 호출되었는지 멤버함수를 호출한 객체의 주소값을 저장한 채 멤버함수의 매개변수로 전달되는 포인터 변수이다.

멤버함수는 다른 모든 멤버변수나 멤버함수에 접근할 때 this포인터를 통해 접근한다. this 포인터는 컴파일러에 의해 자동으로 선언되고 사용되어 진다.

단, 멤버호출시 사용자가 this 포인터를 명시적으로 기술하는 것도 가능하다.

 

1
2
3
4
5
6
7
8
9
10
11
12
class exClass
{
    private:
        int num;
    public:
        void exClass(int num)
        {
            this->num = 200;   // 클래스가 가지고 있는 멤버 변수
            num = 105;         // 함수의 매개변수
        }
        ......
};
cs

 

[예제] 이름과 나이를 대입하는 부분을 함수로 분리한 코드.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>
#include <string.h>
 
struct Friend
{
private :
    char m_name[8];   // 이름
    short int m_age;  // 나이
 
public:
    void InputData()
    {
        strcpy(m_name, "홍길동");  // 이름 대입
        m_age = 20;                // 나이 대입
 
        //Friend *const this;             // this 포인터에는 'data.'에 의해 전달된 주소 저장
        //strcpy(this->m_name, "홍길동"); // 이름 대입
        //this->m_age = 20;
    }
 
    void ShowData()
    {
        printf("내 친구 %s은 %d살 입니다. \n", m_name, m_age);
    }
};
 
void main()
{
    Friend data;        // 객체 인스턴스
    data.InputData();   // 친구의 정보를 받아온다.
    data.ShowData();    //대입된 이름과 나이를 출력한다.
}
cs

friend 함수

class의 private 멤버 변수는 같은 객체의 멤버함수만이 접근 가능하다는 점에서 객체지향 언어의 데이터 은닉성과 캡슐화를 지원한다.

즉, private 멤버 변수의 접근을 class의 내부로 국한시킴으로서 클래스 내부의 수정이 클래스 외부영역에 전혀 영향을 주지 못하기 때문에 프로그램의 유지보수가 쉬워지게 된다. 그러나 경우에 따라서 부득이하게 멤버함수가 아닌 일반함수가 private 멤버에 접근해야 하는 경우가 있다.

이때 사용되는 함수가 friend 함수이다. friend 함수는 일반함수 이면서 클래스의 private 멤버를 호출해 사용할 수 있다.


정적멤버 변수와 정적멤버 함수

정적멤버 변수는 클래스로 만들어진 객체들 사이에서 마치 전역변수와 같이 공용해 사용할 수 있는 멤버 변수이다. 정적멤버 함수도 정적멤버 변수와 같이 모든 객체가 공용해 사용 할 수 있으며 정적멤버 함수와 정적멤버 변수는 객체의 생성과 관계없이 프로그램의 시작과 동시에 만들어 진다.

 

- 정적멤버는 클래스로 만들어진 모든 객체가 공유해 사용 할 수 있는 멤버이다.

- 객체의 생성과 관계없이 프로그램의 시작과 동시에 만들어 지고 프로그램이 종료되면 사라진다.

- 정적멤버 변수가 동작하는 원리와 형태는 전역변수와 동일하다.

단, 정적멤버 변수의 경우 객체지향언어의 데이터 은닉성을 만족시키기 위해 클래스로 만들어진 객체 또는 정적멤버 함수를 통해서만 접근해 사용 할 수 있다.

- 정적멤버 변수는 초기값을 부여 할 수 있다. 단 초기값을 부여하는 행위는 클래스 밖에서 이루어져야 한다.

- 정적멤버 함수는 정적멤버 변수에 대한 접근을 위해 사용한다.

'C++' 카테고리의 다른 글

연산자 오버로딩  (1) 2019.11.27
생성자와 소멸자  (0) 2019.11.27
메모리 구조와 동적 메모리 할당  (0) 2019.11.27
C++이란?  (0) 2019.11.27

[생성자란?]

생성자란 객체를 즉시 사용할 수 있는 상태로 초기화 시켜주는 클래스의 멤버함수이다.

따라서 생성자를 사용하면 생성된 객체의 상태를 일일이 신경을 써 초기화 하지 않고도 사용 할 수 있다.

단, 생성자가 하는 일이 너무 많으면 오히려 코드에 대한 이해도가 복잡해 질수 있음으로 꼭 필요한 작업만 사용하는 것이 좋다.

 

- 클래스로 만들어지는 객체를 초기화 해주는 멤버함수이다.

- 클래스로 객체를 선언할 때 자동적으로 호출된다.

- 사용자가 직접 호출해 사용할 수 없다. (함수의 호출이 명시적이지 않다.)

- 이름은 클래스의 이름과 동일하게 작성해야 한다.

- 리턴 값이 void인 함수이여야 하며 void를 생략하여 함수를 선언하고 정의한다. (리턴 값을 가질 수 없음.)

- 객체 생성 때 마다 호출되어 생성된 객체의 멤버변수를 초기화 시킨다.

- 가상함수로 선언 될 수 없다.

 

생성자 함수의 선언 및 정의 방법

생성자 함수도 멤버 함수임으로 클래스 내에 정의 하면 된다.

또한 다른 멤버함수와 같이 클래스 내부에서는 함수의 선언만 하고 클래스 외부에서 정의하는 것도 가능하다.

1
2
3
4
5
6
7
8
9
//클래스 내부에 생성자 함수를 정의 하는 방법
class 클래스명{
    :
    public:
        클래스명() { //생성자 함수의 정의.  return type을 쓰지 않는다.
            :       //이곳에 생성자 함수의 내용을 기재 한다.
        }
        :           //클래스의 다른 내용
};
cs
1
2
3
4
5
6
7
8
9
10
11
//클래스 내부에는 생성자 함수에 대한 선언을 하고 클래스 외부에 생성자 함수를 정의 하는 방법
class 클래스명{
    :
    public:
        클래스명()   //생성자 함수의 정의.  return type을 쓰지 않는다.
        :           
};
 
클래스명::클래스명() {
    :                //이곳에 생성자 함수의 내용을 기재 한다.
}
cs

 

생성자 함수는 오버로딩이 가능하다.

생성자 함수를 오버로딩 한다면 객체를 선언 할 때 건네준 매개변수 값에 따라 어떠한 생성자 함수가 호출 될지 결정된다.

오버로딩 함수에는 수적 제한이 없으며 매개변수가 없는 생성자 함수를 dafault 생성자 함수라 한다.

1
2
3
4
5
6
7
8
9
/* 예제1 */
Point p1;          // default 생성자 함수가 호출된다.
Point p2(1020);  // 매개변수를 받아가는 생성자 함수가 호출된다.
 
/* 예제2 */
Stud arr[3= { Stud(), Stud(2,25), Stud(3,35) };
arr[0].prn();      // 번호: 0  나이: 0
arr[1].prn();      // 번호: 2  나이: 25
arr[2].prn();      // 번호: 3  나이: 35
cs

[소멸자란?]

소멸자란 객체의 사용이 끝난 후 객체에 대한 뒤처리 작업 등을 자동으로 수행 할 수 있도록 해주는 class의 멤버함수 이다.

소멸자를 사용하면 생성된 객체에 대한 뒤처리를 신경쓰지 않고 편하게 프로그래밍을 할 수 있다.

단, 생성자와 마찬가지로 소멸자 함수가 하는 작업이 너무 많아지면 프로그램의 이해가 어려워지고 오류 발생 위험이 높아지는 등의 문제가 있음으로

꼭 필요한 내용만 소멸자 함수에 포함시키는게 좋다.

 

- 클래스로 만들어지는 객체에 대한 뒤처리를 해주는 멤버함수이다. (뒤처리 작업 = 동적메모리할당 해제)

- 사용중인 객체가 소멸되는 시점에 자동으로 호출된다.

- 직접 호출해 사용할 수 없다.

- 클래스의 이름과 동일하게 작성해야 하되, 생성자 함수와 구분하기 위해 함수명 앞쪽에 ~연산자를 붙인다. (~는 틸드(tilde) 또는 bit not으로 읽으면 된다.)

- 리턴 값이 void인 함수여야 하며 void를 생략하여 함수를 선언하고 정의 한다. (리턴 값을 가질 수 없다.)

- 매개변수를 받아올 수 없다. 따라서 소멸자에 대한 오버로딩이 불가함으로 class 하나에 오직 한 개의 소멸자 함수만 존재해야 한다.

- 객체가 소멸될 때 마다 호출되어 소멸된 객체에 대한 뒤처리 작업을 한다. (전역객체는 프로그램 종료 시 한번, 지역객체는 객체 소멸 시마다 실행된다.)

 

소멸자 함수의 사용방법

소멸자 함수는 객체에 대한 뒤처리를 하기 위해 사용하며 주로 동적 메모리 할당을 자동으로 해제하기 위해 사용한다.

1
2
3
4
5
6
7
8
9
10
//클래스 내부에 소멸자 함수를 정의 하는 방법
class 클래스명{
    :
    public:
        :
        ~클래스명(){ //소멸자 함수의 정의.  return type을 쓰지 않는다.
            :       //이곳에 소멸자 함수의 내용을 기재 한다.
        }
        :           //클래스의 다른 내용
};
cs

[복사생성자란?]

복사생성자란 객체를 만들면서 생성자 함수에 매개변수로 기존에 생성한 객체를 건네줄 경우 컴파일러가 자동으로 생성해주는 생성자 함수이다. 원래 생성자 함수에 어떠한 매개변수를 건네주려면 해당 매개변수를 받아올 수 있는 생성자 함수를 사용자가 직접 만들어야 하지만 객체가 매개변수로 넘어갈 경우에는 사용자가 생성자 함수를 만들지 않아도 컴파일러가 자동으로 복사생성자를 만들어 객체를 매개변수로 받아올 수 있게 해준다.

 

- 컴파일러에 의해 자동으로 생성되는 생성자 함수이다.

- 복사생성자는 객체를 생성자의 매개변수로 받아갈 수 있게 해준다.

- 필요할 경우 사용자가 직접 복사 생성자를 만들어 사용 할 수도 있다.

 

 

복사생성자의 사용방법

사용자가 직접 정의하지 않아도 생성자 함수에 매개변수로 객체를 건네주면 컴파일러가 자동으로 생성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream.h>
 
class Stud {
    private :
        int no;
        int nai;
    public :
        Stud(int x, int y) {
            no = x, nai = y;
        }
        void print() {
            cout << "번호: "<< no << "\t" << "나이: " << nai << endl;
        }
};
 
void main() {
    Stud arr[3= { Stud(115), Stud(225), Stud( arr[1] ) };
    arr[0].print();
    arr[1].print();
    arr[2].print();
}
cs
//실행결과
번호: 1          나이: 15
번호: 2          나이: 25
번호: 2          나이: 25
Press any key to continue

 

 

사용자의 재정의가 필요한 복사 생성자

복사 생성자는 컴파일러가 자동으로 생성하기 때문에 동적메모리 할당을 하는 객체의 경우 복사 생성자에 의해 객체를 만들게 되면 동적메모리 할당 해제 시 문제가 발생할 수 있다. 이러한 문제가 발생 될 것이 예상된다면 사용자는 복사 생성자를 직접 만들어 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//복사 생성자를 직접 정의하여 문제를 해결한 예제
#include <iostream.h>
#include <string.h>
 
class String{
        char *str;
        int len;
    public:
        String(char *);                // 생성자
        ~String();                     // 소멸자
        void cat(String &);            // 전달인자가 객체인 멤버함수
        String(const String &tmp);     // 복사 생성자 재정의
        void prn();
};
 
String::String(char *p) {
    len = strlen(p);
    str = new char[len+1];
    strcpy(str,p);
}
 
String::~String() {
    cout << "Deleting str...\n";
    delete str; // 메모리 해제
}
 
void String::cat(String &s) {
    len = len + s.len;
    char *tmp = new char[len+1];     // 메모리 동적할당
    strcpy(tmp, str);                // 문자열 복사
    strcat(tmp, s.str);              // 문자열 연결
    delete str;                      // 옛 문자열 해제
    str = tmp;
}
 
//복사 생성자 재정의
//복사 생성자는 이미 만들어진 객체를 레퍼런스변수로 받음
String::String(const String &tmp) {
    len = tmp.len;
    str = new char[len+1];
    strcpy(str, tmp.str);
}
 
void String::prn() {
    cout << "문자열: " << str << "(" << len << ")" << endl;
}
 
int main()
{
    String str1("Object-oriented"), str2(str1);
    str1.prn();
    str2.prn();
    str1.cat(str2);
    cout << "\n====문자열 연결====\n");
    str1.prn();
    return 0;
}
cs
//실행결과
문자열: Object-oriented (16)
문자열: Object-oriented (16)

====문자열 연결====
문자열 : Object-oriented Object-oriented (32)
Deleting str...
Deleting str...
Press any key to continue

 

'C++' 카테고리의 다른 글

연산자 오버로딩  (1) 2019.11.27
객체와 friend 함수  (0) 2019.11.27
메모리 구조와 동적 메모리 할당  (0) 2019.11.27
C++이란?  (0) 2019.11.27

C언어의 메모리 구조

프로그램이 실행될 때는 메모리 영역이 4가지로 나뉘어져 할당이 된다.

 

  • 코드영역(Code Area)
    실행되는 프로그램의 코드가 저장되는 메모리 공간. C언어를 통해 작성한 함수, 명령문들이 저장되는 공간
  • 데이터 영역(Data Area)
    전역변수와 정적변수 값이 저장되는 메모리 공간.
    전역변수와 정적변수는 main()문 밖에서 변수를 선언했을 때 만들어지며,
    프로그램을 종료할 때까지 사라지지 않고 메모리 공간에 남아있게 됨.
  • 힙 영역(Heap Area)
    사용자가 원하는 시점에 메모리를 할당하고 소멸하도록 할 수 있는 변수들이 할당되는 영역.
  • 스택 영역(Stack Area)
    지역변수와 매개변수 값이 저장되는 메모리 공간.
    함수 안에서 선언된, 일반적인 변수를 통칭하며 함수가 종료될 때 저장되어 있던 메모리값이 소멸됨.

동적 메모리 할당

프로그램의 실행 중 사용자가 필요한 메모리를 할당받아 사용 할 수 있도록 해주는 기능이다.

메모리 공간 필요 시 할당하고, 사용이 끝난 후 반납을 사용자가 원하는 시점에서 원하는 크기만큼 가능하다.

사용자에 의해 메모리가 동적으로 할당이 되면 프로그램이 끝날 때 까지 유지되므로,

메모리 공간 사용이 끝나면 메모리 낭비(누수)를 줄이기 위해 명시적으로 메모리 할당을 해제 해주어야 한다.

 

*자바에는 가비지 컬렉션이 존재하며 사용되지 않는 메모리를 자동으로 해제해준다.

 C/C++에는 가비지 컬렉션이 존재하지 않으므로 사용자가 명시적으로 메모리를 해제 해 주어야 한다.

 

동적 메모리 할당은 프로그램 실행 중 이루어지며,

프로그램의 작성 시 자료의 크기를 예측하기 어려운 경우 유용하게 사용 할 수 있다.

 

  • 장점: 효율적인 메모리 관리의 기능
  • 단점: 동적 메모리 해제를 해주지 않으면 메모리에 계속 남아 있게 되기 때문에 메모리의 누수가 발생함.

동적 메모리 할당/해제 방법

C 프로그래밍에서는 malloc() calloc() 함수 등을 사용하여 런타임에 메모리를 동적으로 생성하며,

free() 함수를 사용하여 동적으로 할당된 메모리를 명시적으로 해제한다.

 

[C언어의 동적 메모리 할당]

함수 기능
void *malloc(size_t size); size 바이트의 메모리를 힙에서 할당하여 반환한다.
void *calloc(size_t sum, size_t size); (num *size) 바이트의 메모리를 힙에서 할당하고 포인터값을 반환한다.
void *realloc(void *ptr, size_t size); ptr이 가리키는 메모리를 size 바이트만큼 힙에서 재할당하여 반환한다.
void free(void *ptr); 할당 된 메모리를 해제한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
 
void main() {
    int *ip;                    // 동적 메모리 할당한 곳의 주소값을 보관할 포인터 변수를 만든다.
 
    ip = (int *)malloc(4);      // ip에 4바이트의 크기로 동적 메모리 할당을 해 할당한
                                // 곳의 주소값을 넣는다.
    *ip = 10;                   // ip를 역참조해 동적할당한 공간에 10을 집어 넣는다.
    printf("*ip = %d\n"*ip);  // ip를 역참조해 그곳에 있는 값을 출력한다.
    printf(" ip = %d\n",  ip);  // ip를 출력해 동적메모리 할당한 곳의 위치를 출력한다.
 
    free(ip);                   // 동적 메모리 할당을 해제한다.
}
cs

malloc함수는 자신의 뒤쪽 가로 안의 숫자 크기에 해당하는 동적으로 메모리를 할당받아 할당받은 곳의 주소값을 리턴 해준다.
단, 이 주소값은 자료형이 결정되지 않은 void* 형임으로 역참조를 통해 값을 집어넣거나 꺼내올 수 없다.
따라서 강제 형변환을 통해 주소 값의 자료형을 변경 한 후 포인터에 대입해 사용하는 것이다.

 

 

[C++의 동적 메모리 할당]

함수 기능
new

동적할당할 자료형;

동적할당할 자료형[동적할당할 자료의 갯수];

delete

동적할당한 곳의 주소값을 가지는 포인터;

[]동적할당한 곳의 주소값을 가지는 포인터;

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream.h>
 
void main() {
    int *ip;                // 동적 메모리 할당한 곳의 주소값을 보관할 포인터 변수를 만든다.
 
    ip = new int;           // int의 크기를 가지는 공간만큼 동적 메모리 할당을 해
                            // 할당한 곳의 주소값을 ip에 넣는다.
    *ip = 10;               // ip를 역참조해 동적할당 한 공간에 10을 집어 넣는다.
    cout << *ip << endl;    // ip를 역참조해 그곳에 있는 값을 출력한다.
    cout << ip << endl;     // ip를 출력해 동적메모리 할당한 곳의 위치를 출력한다.
 
    delete ip;              // 동적 메모리 할당을 해제 한다.
}
cs

new 연산자는 자신의 뒤쪽에 있는 자료형의 크기만큼 동적으로 메모리를 할당받는다.
자료형을 정해 동적 메모리 할당을 하기 때문에 C언어의 malloc 함수와 같이 강제 형변환을 할 필요가 없고
자료의 형태를 인지하기가 편하다. 동적 메모리 할당한 공간의 사용이 끝났다면 delete 연산자를 이용해
동적 메모리 할당 해제 작업을 한다.


동적 메모리 할당의 활용 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream.h>
#include <string.h>
 
char * input() {
    char inp[100];                      // 이름을 입력받아 저장할 배열을 넉넉한 크기로 만든다.
    cout << "이름을 입력해 주세요 : ";
    oin >> inp;                         // 이름을 입력받는다.
    char *cp;
    cp = new char[strlen(inp)+1];       // 입력받은 이름의 길이보다 1칸 더 크게 cp에
                                        // 동적 메모리 할당을 한다.
    strcpy( cp, inp );                  // 입력받은 이름을 cp에 복사한다.
    return cp;                          // cp를 리턴 한다.
}
 
void main() {
    char *name;
    name = input();                     // input함수에서 리턴받은 값을 name에 저장한다.
    cout << "당신의 이름은 " << name << "입니다." << endl;
    delete name;
}
cs

길이가 얼마일지 모르는 이름을 입력받아 저장하기 위해 input() 함수를 사용하였다.
input 함수는 넉넉하게 큰 배열 inp를 만들어 입력 받은 이름을 보관 한 뒤 입력받은 이름을 보관할 만큼만
동적 메모리 할당 작업을 해 입력받은 문자열을 복사해 넣고, 동적 할당 한 곳의 주소값을 리턴 한다.
input함수는 종료 되면서 함수내에서 선언한 배열과 변수가 모두 사라지지만 동적 메모리 할당한 공간은 사라지지 않는다.
따라서 main함수로 복귀한 뒤에는 입력받은 이름을 보관한 동적 메모리 할당 공간만 남게 된다.

'C++' 카테고리의 다른 글

연산자 오버로딩  (1) 2019.11.27
객체와 friend 함수  (0) 2019.11.27
생성자와 소멸자  (0) 2019.11.27
C++이란?  (0) 2019.11.27

C++의 개념

C언어 + 객체지향 개념 = C++

C++은 C 언어를 포함한다. 때문에 C언어로 작성된 대부분의 프로그램은 C++ 컴파일러로도 컴파일이 가능하다.

그러나 C++은 C언어가 지니지 않는 문법적 특성도 제법 지니고 있다.


C언어와 C++의 차이점

  • 입출력과 관련된 헤더 파일의 변경

    새로운 C++ 표준의 도입으로 인해서 C++의 표준 라이브러리에도 적지 않은 변화가 있었다.
    그리고 새로운 표준 라이브러리의 사용을 목적으로 하는 헤더파일의 포함에는 확장자를 생략하기로 하였다.
  C언어 C++
출력 printf(); std::cout;
입력 scanf(); std::cin;

 

 

  • 지역변수 선언 위치의 자유로움

    C언어로 프로그램을 작성하는 경우에는 함수를 정의함에 있어서 지역변수의 선언이 항상 제일 먼저 등장해야만 했다. 그러나 C++의 지역변수 선언은 함수 내 어디든 삽입이 가능하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
 
int main(void)
{
    //[START] C언어에서의 지역변수 선언 필수 지역
    int val1, val2;
    int result=0;
    //[E N D] C언어에서의 지역변수 선언 필수 지역
    
    std::cout<<"두 개의 숫자입력: ";
    std::cin>>val1>>val2;
    
    if(val1<val2)
    {
        for(int i=val1+1; i<val2; i++)
            result+=i;
    }
    else
    {
        for(int i=val2+1; i<val1; i++)
            result+=i;
    }
    
    std::cout<<"두 수 사이의 정수 합: "<<result<<std:endl;
    
    return 0;
}
cs

//실행결과

//실행결과

두 개의 숫자입력: 3 7

두 수 사이의 정수 합: 15

 

 

  • 함수의 오버로딩(function overloading) - 중복 함수

    같은 이름의 함수를 여러 개 정의하고, 매개변수의 유형과 개수를 다르게 해 다양한 유형의 호출에 응답하는 것.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*
    오버로딩 없이 동일한 기능에 다른 매개 변수를 사용하는 함수를 만드는 방법
    약간 다른 이름으로 여러 함수를 정의한다.
*/
 
int addInteger(int x,int y)
{
    return x+y;
}
 
double addDouble(double x, double y)
{
    return x+y;
}
 
 
/*
    함수 오버 로딩을 사용 시 다른 매개 변수를 취하는 add() 함수를 선언할 수 있다.
*/
 
int add(int x, int y);           //Integer version
double add(double x, double y);  //floating point version
 
//매개 변수의 수가 다른 add()함수도 정의 가능하다.
int add(int x, int y, int z)
{
    return x+y+z;
}
cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//사용 할 수 없는 함수의 오버로딩 기능
int getRandomValue();
double getRandomValue();
 
//결과는 컴파일 오류.
 
 
//1번 해결: 함수에 서로 다른 이름을 지정할 것
int getRandomint();
double getRandomDouble();
 
//2번 해결: 함수가 void를 반환하도록 하고 반환 값을 호출자에게 out 참조 매개 변수로 전달하도록 하는 것
void getRandomValue(int& out);
void getRandomValue(double& out);
cs

위와 같이 처리해야 하는 이유는 오버로딩에서는 함수의 반환 타입이 고려되지 않기 때문이다.

합수는 인수에만 기반하여 호출되는데, 반환 값이 포함된 경우 함수의 어떤 버전이 호출되었는지 쉽게 알기가 어렵다.

 

 

  • 매개변수의 기본 값(Default Value) 추가

    C++ 함수에는 '디폴트 값'이라는 것을 설정할 수 있다. 이것은 말 그대로 기본적으로 설정되어 있는 값이다.
    매개변수에 디폴트 값이 설정되어 있으면 선언된 매개변수의 수보다 적은 수의 인자전달이 가능하다.
    그리고, 전달되는 인자는 왼쪽에서부터 채워져 나가고, 부족분은 디폴트 값으로 채워진다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* DefaultValue2.cpp */
#include <iostream>
int Adder(int num1=1int num2=2);   //디폴트 값은 함수의 선언 부분에만 표현하면 된다.
 
int main(void)
{
    std::cout<<Adder()<<std::endl;
    std::cout<<Adder(5)<<std::endl;
    std::cout<<Adder(3,5)<<std::endl;
    return 0;
}
 
int Adder(int num1, int num2)
{
    return num1+num2;
}
cs

디폴트 값의 선언이 함수의 선언부에 위치해야 하는 이유는 컴파일시 "std::cout<<Adder()<<std::endl;" 문장의 실행이 가능하게 하기 위함이다. 위와 같이 디폴트 값을 전부 지정할 수도 있지만, 부분적인 디폴트 값 설정도 가능하다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int YourFunc(int num1; int num2=5int num3=7){ . . .}
 
YourFunc(10);       //10,  5, 7
YourFunc(1020);   //10, 20, 7
 
 
//디폴트 값 지정이 가능한 함수
int YourFunc(int num1, int num2, int num3=30) { . . . }
int YourFunc(int num1, int num2=20int num3=30) { . . . }
int YourFunc(int num1=10int num2=20int num3=30) { . . . }
 
//디폴트 값 지정이 불가능한 함수
int WrongFunc(int num1=10int num2, int num3) { . . . }
int WrongFunc(int num1=10int num2=20int num3) { . . . }
cs

하지만, 오른쪽 매개변수의 디폴트 값을 비우는 형태로는 디폴트 값을 지정할 수 없다. 함수에 전달되는 인자가 왼쪽에서부터 오른쪽으로 채워지기 때문에 반드시 오른쪽 매개변수의 디폴트 값부터 채우는 형태로 정의해야 한다.

 

 

  • 인라인(Inline) 함수 - 확장 함수

    프로그램 코드라인 안으로 들어가 버린 함수로, C언어에서 사용하는 매크로 함수의 장점은 유지하고,
    단점인 어려운 정의 부분을 해결한 함수이다.

    매크로를 이용한 함수의 인라인화는 전처리기에 의해 처리되지만,
    키워드 Inline을 이용한 함수의 인라인화는 컴파일러에 의해 처리가 된다.

    따라서 컴파일러는 함수의 인라인화가 오히려 성능에 해가 된다고 판단할 경우, 이 키워드를 무시해버리거나 필요한 경우 일부 함수를 임의로 인라인 처리하기도 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**********************************
    매크로 함수
***********************************/
#include <iostream>
#define SQUARE(x) ((x)*(x))
 
int main(void)
{
    std::cout<<SQUARE(5<<std:endl;
    return 0;
}
 
/**********************************
    C++ 기반의 인라인 함수 정의
***********************************/
#include <iostream>
 
inline SQUARE(int x)
{
    return x*x;
}
 
int main(void)
{
    std::cout<<SQUARE(5)<<std::endl;
    std::cout<<SQUARE(12)<<std::endl;
    return 0;
}
cs
//result
25
144

 

단, 매크로 함수에서 데이터 손실이 발생하지 않던 장점이 인라인 함수에서는 적용되지 않는다.

1
2
3
4
5
6
7
8
9
10
/**************************************
    데이터 손실 예제
**************************************/
#define SQUARE(x) ((x)*(x))
 
std::cout<< SQUARE(12);    // int형 함수호출
//변환| std::count<< ((12)*(12));
 
std::cout<< SQUARE(3.15);  // double형 함수호출
//변환| std::count<< ((3.15)*(3.15));
cs

 

 

  • 이름공간(namespace)의 추가

    이름공간과 범위 지정 연산자 ::(scope)의 추가로 동일한 이름의 func을 지정하여 사용할 수 있게 되었다.
    이름공간은 중첩하여 사용 할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
 
namespace Koscom1
{
    void SimpleFunc(void);
}
 
namespace Koscom2
{
    void SimpleFunc(void);
}
 
int main(void)
{
    Koscom1::SimpleFunc();
    Koscom2::SimpleFunc();
    return 0;
}
 
void Koscom1::SimpleFunc(void)
{
    std::cout<<"Koscom1이 정의한 함수"<<std::endl;
}
 
void Koscom2::SimpleFunc(void)
{
    std::cout<<"Koscom2이 정의한 함수"<<std:endl;
}
cs

 

콘솔 입출력 진행 시 사용하던 것들도 이름공간을 이용하여 선언된 것이라는 것을 유추해 볼 수 있다.
이름공간을 명시하는 방법에는 using도 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
 
int main(void)
{
    int num=20;
    cout<<"Hello World!"<<endl;
    cout<<"Hello "<<"World!"<<endl;
    cout<<num<<' '<<'A';
    cout<<' '<<3.14<<endl;
    return 0;
}
cs
//result
Hello World!
Hello World!
20 A 3.14

 

using 선언을 일괄적으로 하는 방법은 "using namespace std;"를 해주면 된다.

하지만, 이런 일괄선언 방식은 이름충돌이 발생할 확률이 상대적으로 높아지는 현상이 발생한다.

따라서, 무조건 편한 것만을 선호하기 보다는 적용 할 소스에 적정하게 판단하여 사용하는 것이 필요하다.

 

이름공간의 별칭 지정이 가능하므로, 중첩되는 이름공간이 많아졌을 때는

호출 시 편리성을 촉진시키기 위해 호출하는 이름공간에 별칭을 부여 할 수 있다.

가령 AAA::BBB::CCC::num1 = 10;을 호출한다면 namespace ABC=AAA::BBB::CCC;로 별칭을 선언 할 수 있다.

ABC::num1=10;도 동일하게 변수로 사용 할 수 있다.

 

범위지정 연산자 :: (scope)로 중복 이름의 전역변수 호출도 가능하다.

1
2
3
4
5
6
7
8
int val=100;    // 전역변수
 
int SimpleFunc(void)
{
    int val=20// 지역변수
    val+=3;     // 지역변수 val의 값 3 증가
    ::val+=7;   // 전역변수 val의 값 7 증가
}
cs

 

 

  • 새로운 자료형 bool의 등장

    bool에서는 '참'을 의미하는 true와 '거짓'을 의미하는 false가 있다.
    이것을 가리켜 bool형 데이터라 한다.
    그리고, bool은 int, double과 마찬가지로 기본자료형의 하나이기 때문에 bool형 변수로 선언이 가능하다.

    true와 false는 그 자체로 참과 거짓을 의미하는 데이터이기 때문에,
    이들 데이터의 저장을 위한 자료형이 별도로 정의되어 있는 것은 당연하다.
1
2
bool isTrueOne=true;
bool isTrueTwo=false;
cs

 

 

  • 참조자(Reference) = 별칭

    참조자는 자신이 참조하는 변수를 대신할 수 있는 또 하나의 이름이다.
    참조자의 수에는 제한이 없으며, 참조자르 대상으로도 참조자를 선언할 수 있다.
    단, 참조자의 선언 가능 범위는 정해져 있으며 변수와 비슷한 기능을 하지만, 혼자 스스로 선언 될 수 없다.

    무조건 변수를 참조하여 선언해야 한다.

프로그램의 구조

프로그램은 일반적으로 세 가지 기본 요소로 구성된다.

명령문(statement)

표현식(expression)

함수(function)

 

 

  • 명령문(statement)

    프로그램에서 가장 일반적인 구조이며 C++에서 명령문은 가장 작은 단위이다.
    생각을 전달하기 위해 사용하는 문장과 유사하며, C++에서는 컴파일러에게 작업을 수행하기 위해 명령문을 작성한다.
1
2
3
4
5
/* 명령문 예제 */
 
int x;          //선언문(declaration statement), x가 정수(int) 형태의 값을 보유하는 변수임을 컴파일러에게 알린다.
x=5;            //변수 x에 값 5를 할당하여 나중에 이 값을 사용할 수 있도록 하는 명령문이다.
std::cout << x; //변수 x의 값을 콘솔에 출력하는 명령문이다.
cs

 

  • 표현식(expression)

    컴파일러는 표현식을 해석할 수 있다. 표현식은 수행할 계산을 지정한다.
    예를 들어, 프로그램에서 2+3 값은 5로 평가되는 표현식이다.

    표현식은 리터럴(literal) 값 2나 텍스트를 나타내는 "Hello, world" 및 변수, 수학 연산자(+)와 함수 호출을 포함한다.
    x=5는 변수 x에 5의 값을 할당하는 유효한 표현식이다. (세미콜론은 없다.)

    표현식은 명령문 내에서 사용되기 때문에 자체적으로 컴파일 될 수 없다.
    예를 들어 x=5 라는 표현식을 컴파일하려고 하면 세미콜론이 빠졌으므로 에러가 발생한다.
1
2
3
4
5
6
7
2
"Hello, world"
x
2+3
x=5
(2+x)*(y-3)
std::cout << x
cs

 

  • 함수(Function)

    C++에서 명령문은 함수라고 하는 단위로 그룹화된다. 즉, 함수는 순차적으로 실행되는 명령문의 집합이다.
    모든 C++ 프로그램에는 main이라는 특수 함수가 있어야 하며, 프로그램이 실행될 때 main 함수 내부의 첫 번째 명령문부터 시행이 시작된다.

'C++' 카테고리의 다른 글

연산자 오버로딩  (1) 2019.11.27
객체와 friend 함수  (0) 2019.11.27
생성자와 소멸자  (0) 2019.11.27
메모리 구조와 동적 메모리 할당  (0) 2019.11.27



egov-com-servlet.xml


<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" p:order="3">

<property name="mappings">

<props>

<prop key="/sub/sub01/page*.do">sub01ViewController</prop>

</props>

</property>

</bean>


<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />

<bean id="sub01ViewController" class="org.springframework.web.servlet.mvc.UrlFilenameViewController" p:prefix="/sub/sub01/" p:suffix="" />


-----------------------------------------------------------------------------------------------------------------------------------------------

key : 호출할 mapping URL

<prop></prop>사이에 viewController Id를 적어준다.


bean

id : prop에 선언한 viewController Id

p:prefix : 컨텐츠 경로




'etc.' 카테고리의 다른 글

[eclipse] 이클립스 블럭 주석 설정/해제 단축키  (0) 2016.09.28
[Toad] 주석 단축키  (0) 2016.09.27
[eclipse] out of memory 날 때 조치방법  (0) 2016.09.01



datepicker로 input text의 value값을 바꾼 후 체크하는 스크립트를 태워야 할 때

value에 바로 박힌 값은 onchange로 체크가 불가능하다.


그럴 때는


$(document).ready(function(){

$('#teqst').datepicker({

onSelect: function(dateText, inst){

chkSet('1111',0);

}

});

});




onSelect {} 안에 진행할 스크립트 소스를 넣어준다.


그럼 datepicker 스크립트 실행 후 넣어준 소스 스크립트를 진행한다.


<style type="text/css">

.agree_box_span {font-weight:bold;text-decoration:underline;}

</style>



태그 열고, 닫고 안에

클래스명 {클래스 속성}


작성해주면 끝.


egovframework에서 showModalDialog가 크롬에서 적용안될 때 대체 사용 기능을 제공한다.


URL : https://www.egovframe.go.kr/wiki/doku.php?id=egovframework:com:v3:cmm:showmodaldialog


JavaScript의 Modal 방식의 dialog를 지원하는 windows.showModalDialog의 기능이 chrome 37 버전부터 지원하지 않음에 따라 대체 기능을 제공한다.


js파일을 제공하며, 이미 공통 js를 쓰고있는 경우에는 공통 js 코드만 추가해주면 별도의 script 선언없이 공통적용도 가능하다.


▼ 아래는 공통관련 부분 내용이다.


6. 공통 js 파일을 통해 처리하는 경우 js 파일 처리

공통 js를 통해 공통 기능이 제공되는 경우 원 js 파일에 대하여 다음과 처리하면 개별 JSP 파일에 <script>를 추가하실 필요는 없음

다음과 같이 활용할 수 있다.

function dirname(path) {
	if (path.lastIndexOf("/") == -1)
		return "./";
	return path.replace(/\\/g, '/').replace(/\/[^\/]*\/?$/, '') + "/";
}
 
function getActiveScript() {
	var d = document.getElementsByTagName("script");
	var path = dirname(d[d.length - 1].src);
	delete d;
 
	var offset=path.indexOf(location.host)+location.host.length;
	return path.substring(offset);
} 
 
 
function getContextPath(){
    var offset=location.href.indexOf(location.host)+location.host.length;
    var ctxPath=location.href.substring(offset, location.href.indexOf('/',offset+1));
 
    if ((/^\/js/).test(getActiveScript())) {
    	return "";
    }
 
    return ctxPath;
}
 
function loadScript(src, f) {
  var head = document.getElementsByTagName("head")[0];
  var script = document.createElement("script");
  script.src = src;
  var done = false;
  script.onload = script.onreadystatechange = function() { 
    // attach to both events for cross browser finish detection:
    if ( !done && (!this.readyState ||
      this.readyState == "loaded" || this.readyState == "complete") ) {
      done = true;
      if (typeof f == 'function') f();
      // cleans up a little memory:
      script.onload = script.onreadystatechange = null;
      head.removeChild(script);
    }
  };
  head.appendChild(script);
}
 
loadScript(getContextPath() + '/js/egovframework/com/cmm/showModalDialog.js');




문자 > 숫자


Integer.parseInt(ㅇㅇㅇ);



숫자 > 문자

ㅇㅇㅇ.toString();



'JAVA' 카테고리의 다른 글

반복문 for 두가지 방법  (0) 2016.09.20

+ Recent posts