도움을 주신분들 정말 감사합니다.
1. class
class란 C의 구조체에 멤버로 함수를 넣은것?(이렇게 설명해도 될려나)
멤버로 멤버변수 및 멤버 함수를 갖는것..class
#include <iostream>
using std::cout;
using std::endl;
struct Account{
char accID[20];
char secID[20];
char name[20];
int balance;
};
void Deposit(Account &acc,int money)
{
acc.balance+=money;
}
void Withdraw(Account &acc,int money)
{
acc.balance-=money;
}
이렇게 되어있는 C스타일의 구조체와 함수를 하나로 묶어줄수 있다..무엇으로? class로
struct Account{
char accID[20];
char secID[20];
char name[20];
int balance;
void Deposit(int money)
{
balance+=money;
}
void Withdraw(int money)
{
balance-=money;
}
};
아직은 class가 아니다..C++에서 지원하는 구조체의 형태이다.
C++에서는 구조체 안에 함수가 존재할수 있도록 허락해준다..좋은놈..
자 드디어 우리의 class등장!!
class Account{
public:
char accID[20];
char secID[20];
char name[20];
int balance;
void Deposit(int money)
{
balance+=money; // balance는 class내의 변수를 참조한다.(내부접근)
}
void Withdraw(int money)
{
balance-=money;
}
};
class다..구조체와 다른게 없다고 생각되는가?..
선언만 struct --->class로 해줬고..public하나 해줬고..
그게 차이다. 구조체는 기본값이 public이다. 즉 외부접근이 허용이된다.
그러나 class는 기본값이 private이다..저렇게 위처럼 public를 허용해 주지 않으면
내부접근만 가능하고..기본적으로는 private이기때문에 외부접근이 불가능하다.
그리고class는 더이상 변수라는 표현을 쓰지 않고 "객체"라는 표현을 쓴다..
멤버함수의 외부정의
위에처럼 정의를 하면 class의 가독성이 현저하게 떨어지므로 함수의 선언만 하고
정의는 외부에다가 할수가 있는데 그때 사용하는 것이 범위지정연산자(::)이다.
class Account{
public:
char accID[20];
char secID[20];
char name[20];
int balance;
void Deposit(int money);
void Withdraw(int money);
};
void Account::Deposit(int money)
{
balance+=money;
}
void Account::Withdraw(int money)
{
balance-=money;
}
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
typedef int element;
typedef struct DlistNode{
element data;
struct DlistNode* llink;
struct DlistNode* rlink;
}DlistNode;
void init(DlistNode* phead)
{
phead->llink=phead;
phead->rlink=phead;
}
void display(DlistNode* phead)
{
DlistNode* p;
for(p=phead->rlink ; p!=phead ; p=p->rlink)
{
printf("<---| %x | %d | %x |--->\n",p->llink , p->data, p->rlink);
}
printf("\n");
}
main()
{
DlistNode head_node;
DlistNode* p[10];
int i;
init(&head_node);
for(i=0 ; i<5 ; i++)
{
p[i] = (DlistNode*)malloc(sizeof(DlistNode));
p[i]->data = i;
dinsert_node(&head_node,p[i]);
}
dremove_node(&head_node,p[4]);
display(&head_node);
}
1. const 키워드 사용법
const int n=10; //n값의 변경 불가능
int a=10;
int b=20;
const int* p=&a; // 포인터p가 가리키는 변수 a를 상수화 시킨다.
// 포인터p가 a를 바라봤을때 상수처럼 보인다..
// *p=30 (x) a=20(o)
int* const p=&a; // p라는 값 자체를 상수화 시킴
// 프로그램이 종료될때까지 p는 a라는 변수를 가리키고 있어야함.
// p=&b (x) *p=30(o)
const int* const p=&a; //위의 두가지 기능을 다 가짐
2. bool
bool형 변수는 true 와 false 키워드가 기본적으로 제공된다.
int형의로 변환시 1과0 이 되지만 true 와 false 는 bool형 데이터로 인정해줘야함.
3. 레퍼런스(reference)
int val=0;
int &ref=val;
val이라는 변수이름에 ref라는 별명을 붙여준개념.
레퍼런스와 변수는 생성방법에서만 차이를 보일뿐 일단 만들어지고 나면 완전히 같음.
다만..
int &ref;
int &ref=10;
이런식의 선언은 불가..변수가 선언된다음에야 레퍼런스 선언이 가능.
레퍼런스를 이용한 call-by-reference.
#include <iostream>
using std::cout;
using std::endl;
void swap(int &a,int &b) // 레퍼런스의 형태로 받아주므로
{ // 스왑연산이 가능하다.
int temp=a; // 일반함수형태의 값의 복사(call-by-value)가 아닌
a=b; // 레퍼런스로 연산하는 call-by-reference
b=temp;
}
int main()
{
int val1=10;
int val2=20;
cout<<"val1 = "<<val1<<endl;
cout<<"val2 = "<<val2<<endl;
swap(val1,val2); // 함수호출시 일반함수와 차이를 알아보기힘듬
cout<<"val1 = "<<val1<<endl;
cout<<"val2 = "<<val2<<endl;
return 0;
}
단점은 함수호출시 일반함수와의 차이를 알아보기 힘들다.
장점은 함수호출시 매개변수의 복사가 이루어지지 않고 레퍼런스로
연산이 가능하기때문에 메모리공간의 효율성
다만..함수의 매개변수에서 상수화시켜 받아주는 센스가 필요함.
설명->매개변수로 받는값에 p라는 별명을 붙여준 값을 상수화하여 함수를연산하라.
레퍼런스의 return
#include <iostream>
using std::cout;
using std::endl;
int& increment(int &val) // 변수n에 val이라는 별명을 붙여주고
{
val++;
return val; // 그 별명값을 리턴하라..리턴형은 int의 레퍼런스
}
int main()
{
int n=10;
int &ref=increment(n); // int의 레퍼런스형태로 함수를 받아주고 있다.
cout<<"n : "<<n<<endl;
cout<<"ref: "<<ref<<endl;
return 0;
}
레퍼런스 리턴시 잘못된 함수
#include <iostream>
using std::cout;
using std::endl;
int& function(void)
{
int val=10;
return val;
}
int main()
{
int &ref=function();
cout<<"ref: "<<ref<<endl;
return 0;
}
main함수 내에 변수가 선언이 되지 않았고..
function함수 내에서 선언된 int형 변수 val은 함수가 호출되고 종료되는 순간에
스택에서 사라지므로 딱봐도 말이 좀 안된다...
지역변수를 레퍼런스로 리턴하는 일은 없어야 한다.
4. new & delete
C언어의 malloc,free함수를 C++에서는 new와 delete가 대신한다.
C : int* arr=(int*)malloc(sizeof(int)*size)); 이런식으로 선언함
malloc함수가 리턴하는 값이 void형 포인터이기때문에 형변환을 해주어야함.
C++ : int* arr = new arr[size];
new연산자는 용도에 맞게 포인터를 반환하므로 형변환을 할 필요가없다.
다만 배열의 메모리반환시에
delete []arr;
로 선언을 해주어야한다.2차원이건 3차원이건 같다.
메모리 할당 실패시 new연산자는 NULL포인터를 리턴한다.
typedef int element;
typedef struct ListNode{
element data;
struct ListNode* link;
}ListNode;
/*void error(char* message)
{
fprintf(stderr,"%s\n",message);
exit(1);
}
*/
ListNode* create_node(element data, ListNode* link)
{
ListNode* new_node;
new_node = (ListNode *)malloc(sizeof(ListNode));
if(new_node == NULL){
fprintf(stderr,"메모리할당에러");
exit(1);
}
new_node->data=data;
new_node->link=link;
return (new_node);
}
void insert_first(ListNode **phead , ListNode* node)
{
if(*phead==NULL){
*phead=node;
node->link=node;
}
else
{
node->link=(*phead)->link;
(*phead)->link=node;
}
}
void insert_last(ListNode **phead , ListNode* node)
{
if(*phead==NULL){
*phead=node;
node->link=node;
}
else
{
node->link = (*phead)->link;
(*phead)->link = node;
*phead = node;
}
}
void display(ListNode *head)
{
ListNode *p;
if( head == NULL) return;
p = head;
do{
printf("%d->",p->data);
p = p->link;
}while(p != head);
printf("\n");
}
main()
{
ListNode *list1=NULL;
insert_first(&list1,create_node(10,NULL));
insert_first(&list1,create_node(20,NULL));
insert_last(&list1, create_node(30,NULL));
display(list1);
}
1. C++입 출력방식
<iostream.h>방식
cout<<출력대상1<<출력대상2 ;
cin>>입력대상1>>입력대상2 ;
endl; 개행및 출력버퍼 비워줌
<iostream>방식
std::cout<<출력대상1<<출력대상2 ;
std::cin>>입력대상1<<입력대상2 ;
std::endl;
같으나 새로개정된ANSI표준 앞에std::를 붙여주거나
using std::cout;
using std::cin;
using std::endl;
로 정의 가능
using namespace std::로도 한번에 정의 가능하나 나중에 이름충돌가능성있음
2. 함수 오버로딩
C++에서는 함수 오버로딩이 지원됨.
즉, 함수의 이름이 같아도 컴파일러가 알아서 판단.
하지만 매개변수의 개수 및 타입이 달라야함.
리턴 타입만 다르고 함수이름 및 매개변수가 같을경우에도 적용이 안됨.
3. 디폴트 매개변수
int function(int a=0)
{
return a*7;
}
에서와 같이 함수 매개변수 부분에 디폴트 매개변수사용 가능.
매개변수가 없을경우 0을 디폴트 값으로 설정해줌
매개변수값이 있을경우에는 그값을 설정.
주의할점
이럴경우 함수 2개가 동시에 호출이 되기때문에 주의해야함
함수오버로딩과 디폴트 매개변수를 동시에 잘못정의.
4. inline 함수
C언어의 매크로와 같은 기능을 가진 함수
다만 매크로는 전처리기에 의해 처리가 되고
inline함수는 컴파일러에 의해 처리가 됨.
inline함수는 컴퓨터가 판단하여 성능향상에 해가된다고 판단될 경우
그냥 무시해버리기도한다.
함수이름앞에 그냥 inline 키워드를 붙여주기만 하면됨.
5. namespace
이름 공간이 다르면 같은 변수나 함수의 선언이 허용된다.
예를 들어
#include <iostream>
namespace A_COM
{
void function(void)
{
std::cout<<"A.COM에서 정의한 함수"<<std::endl;
}
}
namespace B_COM
{
void function(void)
{
std::cout<<"B.COM에서 정의한 함수"<<std::endl;
}
}
int main()
{
A_COM::function();
B_COM::function();
return 0;
}
이런 식으로 가능(이건 이렇게 예제로 밖에 설명할수가 없군 -_-;)
cout,cin,endl 도 std라는 네임스페이스 안에서 정의된 것들.
6. using
1번에서 설명
return 1; ㅋㅋㅋ
7. :: 범위지정 연산자
전역변수에 접근하기 위해서도 사용됨
#include <iostream> //구버젼은 <iostream.h>
//usiong namespace std; 가능
using std::cout;
using std::endl;
//네임스페이스 생성
namespace JS
{
int function(int a,int b,int c)
{
std::cout<<"네임스페이스function(int a,b,c)"<<std::endl;
return 0;
}
}
//using
using JS::function;
//함수오버로딩
int function(int a=0)// 디폴트매개변수선언 : 매개변수에 전달되는값이 없으면 0 으로 초기화
{
std::cout<<"function(int a)"<<std::endl;
return 0;
}
int function(int a, int b)
{
cout<<"function(int a,int b)"<<endl;
return 0;
}
//inline 함수 : 매크로와 달리 컴파일러에 의해 처리되기때문에 최적화가 용이
inline int SQUARE(int x)
{
return x*x;
}
int main()
{
JS::function(1,2,3);//JS네임스페이스의 함수 호출
function(1,2,3);
function(1);
function(1,2);
return 0;
}