상속이란 객체의 특성을 물려받는 개념이다.
상속의 대표적 관계
#is-a 관계 : 아주 지극히 당연한 관계조건이다. ~~는 ~이다 라는 조건하에 이루어지는 상속으로 상위 클래스를 상속할경우 기능과 특성이 세밀해지며 작은 단위의 클래스를 형성할수 있게된다.
예)
- 경찰은 사람이다. : 경찰이 사람 클래스를 상속하는 경우.
- 자동차는 기계이다. : 자동차가 기계클래스를 상속하는경우.
등등...
#has-a 관계 : 소유적 관계이며 is-a 관계와는 또다른 상속의 개념이다. 상속 키워드를 사용해서 상속하는방법 뿐만이 아니라 맴버데이터로 객체나 포인터객체를 사용함으로써 포함하는 관계를 성립할수도 있다는 것이다.
예)
- 경찰은 권총을 소유한다. : 경찰 클래스내 데이터에 권총 클래스의 객체를 생성하는 경우.
등등...
대략.. 많은 경험이 없기때문에 여기까지 떠들고 코딩하러감 ㅇㅅㅇ
'프로그래밍/C / C++'에 해당되는 글 29건
- 상속관계 (1) 2008/05/23
- 문자관련 함수 라이블러리 // ctype.h 2008/04/23
- EOF - end of file 2008/04/18
- const 변수, 함수, 객체....... 2008/04/17
- 복사 생성자 , c++ style....; 2008/04/17
| 함수 이름 | 리턴 값 |
|
isalnum() |
전달인자가 영문자이거나 숫자일경우 true값을 반환한다. |
| isalpha() | 전달인자가 영문자[소문자 + 대문자] 일경우 true값을 반환한다. |
| isdigit() | 전달인자가 숫자[0~9] 일경우 true값을 반환한다. |
| isxdigit() | 전달인자가 16진수[0~9 , a~f , A~F]이면 true를 반환한다. |
| islower() | 전달인자가 소문자[a~z] 일경우 true값을 반환한다. |
| isupper() | 전달인자가 대문자[A~Z] 일경우 true값을 반환한다. |
| ispunct() | 전달인자가 구두점일경우 true값을 반환한다. |
| isspace() | 전달인자가 화이트스페이스[공백,엔터,케리지리턴,수평탭,수직탭,용지이송] 일경우 true값을 반환한다. |
| iscntrl() | 전달인자가 제어문자일경우 true값을 반환한다. |
| isascii() | 전달인자가 아스키코드일경우 true값을 반환한다. |
| isgraph() | 전달인자가 빈칸이 아닌 인쇄할 수 있는 문자일경우 true값을 반환한다. |
| isprint() | 전달인자가 인쇄가능한 문자일경우 true값을 반환한다. |
| tolower() | 전달인자가 대문자이면 소문자로 바꾸어서 리턴한다. 그렇지 않을경우 그냥 리턴한다. |
| toupper() | 전달인자가 소문자이면 대문자로 바꾸어서 리턴한다. 그렇지 않을경우 그냥 리턴한다. |
위 함수들은 매우 활용적이다 가령
if((ch >= 'a' || ch <= 'z') || (ch >= 'A' || ch<= 'Z')) 이런 조건문은 if(isalpha()) 라고 표시하는것과 전혀 다르지 않으며 프로그램의 가독성을 향상시켜줄수 있다.
cctype라이블러리의 함수를 사용한 예제
댓글을 달아 주세요
EOF = -1라고 쓰이며 파일의 끝을 나타내는 조건자로 쓰인다.
Ctrl + Z 또는 Ctrl + D키워드로 사용하는데 내가 사용하는 xp에선 Ctrl + Z으로 쓰이는듯...
cin객체는 EOF를 탐지하면 eofbit과 failbit의 비트를 1로 설정한다. [eofbit , failbit은 나도 잘 모르지만 무언가 어떤 특정 값을 1로 변환하는듯..; 그렇다면 변환이 됬는지 안됬는지 확인해볼 필요가 있다. 확인 방법은 cin객체의 eof()메서드를 통해서 확인이 가능하다.
#include<iostream>
using std::cout;
using std::endl;
using std::cin;
int main(){
int x;
cin>>x;
cout<<"현제 eofbit과 failbit은 "<<cin.eof()<<"로 설정되어 있습니다"<<endl;
return 0;
}
using std::cout;
using std::endl;
using std::cin;
int main(){
int x;
cin>>x;
cout<<"현제 eofbit과 failbit은 "<<cin.eof()<<"로 설정되어 있습니다"<<endl;
return 0;
}
cin.eof()메서드는 입력된 값의 여부에따라 eofbit과 failbit을 설정한다. 만약 Ctrl + Z [EOF]를 입력하면 1로 설정되었다고 출력할것이다. cin.eof()가 eofbit의 bit문자를 제외한 eof라면 fail도 마찬가지로 cin.fail()메서드가 존재한다. cin.fail()메서드는 eofbit과 failbit이 1로 설정되어있을경우 bool값 true를 리턴한다. 이와 반대로 0으로 설정되어있으면 당연히 false를 리턴한다.
위 얘기를 정리하면 cin.eof()가 실행된다음 cin.fail()가 그것을 확인하는 순서로 이루어진다.
EOF를 이용한 탈출루프 구현
#include<iostream>
using std::cout;
using std::endl;
using std::cin;
int main(){
cout<<"Ctrl + Z 을 누르면 프로그램을 종료합니다."<<endl;
int ch;
ch = cin.get();
while(cin.fail() == false){
cout.put(ch);
ch = cin.get();
}
return 0;
}
using std::cout;
using std::endl;
using std::cin;
int main(){
cout<<"Ctrl + Z 을 누르면 프로그램을 종료합니다."<<endl;
int ch;
ch = cin.get();
while(cin.fail() == false){
cout.put(ch);
ch = cin.get();
}
return 0;
}
댓글을 달아 주세요
const 키워드를 붙이면 변수를 상수화 한다.... "상식"이 되어버렸지만 변수 이외에 포인터 , 맴버데이터 , 함수 ,객체까지 확장할경우 의미가 넓어진다. 하지만 진정한 const의 의미는 안정적인 프로그래밍 코드구현에 있다.
일단 기본 상식인 변수와 포인터 를 const화 시키는건 요약글로 묶어두고... ㅋ
const 포인터 변수 짬깐 들여다보기 ㅋㅋ
const키워드와 맴버데이터
기본적인 변수를 상수화 시키는것과 같은 이치다. 하지만 맴버데이터이니만큼 어떻게 초기화 시키는지쯤은 알고 넘어가야 하겟다.
작성법 : 일반 변수와 같이 const키워드를 앞에 붙여주면된다.
#include<iostream>
using std::cout;
using std::endl;
class test{
const int num;
public:
test(int _num){
num = _num;
}
void print(){
cout<<"num = "<<num<<endl;
}
};
int main(){
test work(10);
work.print();
return 0;
}
using std::cout;
using std::endl;
class test{
const int num;
public:
test(int _num){
num = _num;
}
void print(){
cout<<"num = "<<num<<endl;
}
};
int main(){
test work(10);
work.print();
return 0;
}
그래서 나온것이 "이니셜라이져" 라고하는 초기자이다.
초기자를 사용하여 const화된 맴버데이터를 초기화 하는 올바른 test 클래스
class test{
const int num;
public:
test(int _num):num(_num){
}
void print(){
cout<<"num = "<<num<<endl;
}
};
const int num;
public:
test(int _num):num(_num){
}
void print(){
cout<<"num = "<<num<<endl;
}
};
초기자는 함수의 몸체부분이 실행되기전에 먼저 실행된다.
그렇다면 왜 초기자를 사용해야할까? 클래스내부에서 초기화할순 없는건가?... 라고 생각하는 사람들이 많은데.... -ㅅ-; 구조체 내부에서 값을 초기화 할수있었나?? 불가능했다. 클래스또한 마찬가지이다.
그렇다면 왜 생성자에서 초기화 할까? 메모리구조상 객체를 찍어내는 순간 그 객체를 메모리공간에 올라가는데 이와 동시에 생성자를 호출한다. 하지만 초기자는 생성자 이전에 실행되기때문에 미리 맴버데이터를 초기화시켜줄수있게 되는것이다.
초기자의 사용방법 : 함수(자료형 매개변수) : const변수(매개변수) , ....{} 라고 적어주면된다.
ex)
class test{
const int num;
int x;
int y;
public:
test(int _num , int _x , int _y ):num(_num) , x(_x) , y(_y){
}
void print(){
cout<<num<<x<<y<<endl;
}
};
const int num;
int x;
int y;
public:
test(int _num , int _x , int _y ):num(_num) , x(_x) , y(_y){
}
void print(){
cout<<num<<x<<y<<endl;
}
};
const 키워드와 맴버함수
맴버함수의 상수화는 곳 그함수내에서는 데이터에 관한 어떤 조작도 할수없을 뿐더러 값조작의 기회조차 주지 않음을 의미한다.
작성법 : const 키워드를 함수 머리 뒷부분에 적어줌으로써 함수를 상수화 시키는면된다.
#include<iostream>
using std::cout;
using std::endl;
class test{
int Notouch;
public:
test():Notouch(10){ //변수(값)은 C++스타일의 초기화방법
}
void print() const{
cout<<Notouch<<endl;
Notouch++; //컴파일 에러!!
}
};
int main(){
test work;
work.print();
return 0;
}
using std::cout;
using std::endl;
class test{
int Notouch;
public:
test():Notouch(10){ //변수(값)은 C++스타일의 초기화방법
}
void print() const{
cout<<Notouch<<endl;
Notouch++; //컴파일 에러!!
}
};
int main(){
test work;
work.print();
return 0;
}
상수화된 맴버함수는 값 조작 권한을 잃는다.
아래 또하나의 코드를 통해 상수화된 두 함수간의 관계를 알수있다. 안봐도 되지만 본다면 ㅋㅋ
#include<iostream>
using std::cout;
using std::endl;
class test{
int Notouch;
public:
test():Notouch(10){
}
void print() const{
cout<<Notouch<<endl;
Notouch++; //컴파일 에러!!
print2(); //컴파일 에러!!
}
void print2(){
cout<<Notouch<<endl;
}
};
int main(){
test work;
work.print();
return 0;
}
using std::cout;
using std::endl;
class test{
int Notouch;
public:
test():Notouch(10){
}
void print() const{
cout<<Notouch<<endl;
Notouch++; //컴파일 에러!!
print2(); //컴파일 에러!!
}
void print2(){
cout<<Notouch<<endl;
}
};
int main(){
test work;
work.print();
return 0;
}
컴파일에러가 뜨는이유는 print2함수에서 맴버데이터를 조작할 가능성이 있기때문이다. 프로그래머가 보기에는 print2함수에선 아무 데이터 조작도 하지않지만 컴파일러는 그렇게까지 관대하지 못하기때문에 확실함을 요구하는 차원에서 에러를 띄워주는 것이다. 또하나의 이유는 값조작이며 위에서 언급했으므로 pass~
올바른 클래스
class test{
int Notouch;
public:
test():Notouch(10){
}
void print() const{
cout<<Notouch<<endl;
//Notouch++;
print2();
}
void print2() const{
cout<<Notouch<<endl;
}
};
int Notouch;
public:
test():Notouch(10){
}
void print() const{
cout<<Notouch<<endl;
//Notouch++;
print2();
}
void print2() const{
cout<<Notouch<<endl;
}
};
이를 토대로 const함수는 const함수만 호출이 가능함을 알수있다.
const 키워드와 객체
상수화된 변수처럼 사용하면된다. 상수화된 객체는 맴버데이터의 변경이 절대적으로 불가능해진다.
작성법 : const 클래스 객체;
#include<iostream>
using std::cout;
using std::endl;
class test{
const int val;
public:
test(int _val):val(_val){
}
void print() { //컴파일 에러!!
cout<<val<<endl;
}
};
int main(){
const test work(10);
work.print();
return 0;
}
using std::cout;
using std::endl;
class test{
const int val;
public:
test(int _val):val(_val){
}
void print() { //컴파일 에러!!
cout<<val<<endl;
}
};
int main(){
const test work(10);
work.print();
return 0;
}
이유는 즉, 상수화의 의미를 이해하면되는데,,; 값조작을 허용치않는 객체에서 값 조작이 가능한 비 상수화 함수를 호출했다고 가정할경우 맴버데이터값이 변하게되는 원치않는 일이 발생할수있기 때문이다. 컴파일러는 이런 상황이 일어나지않을수 있음에도 불구하고 자비롭지못해 에러를 내뱉는다.
생성자도 함수인데 그럼 생성자도 const화 시킬수있나요? 그건 나도 잘모르겠지만 생성자를 상수화 시키는건 의미없는 행위같다. 생성자의 진정한 의미는 맴버데이터의 값을 조작하기 위함인데 그것마저 const화시킨다면...; 물론 초기자를 이용해서 값을 바꿀수도 있지만 쪕 -ㅅ-;;; 쫌 거지같은 const;; 아 .. 얘기가 딴대로 흘럿네.. 암튼!
여기서 또 오버로딩의 개념이 나오는데 상수화된 객체와 비 상수화된 객체가 맴버함수를 호출할때 인자값이 같을경우 어떻게 오버로딩을 하느냐?! ㅋㅋㅋ 바로 const키워드를 붙이느냐 안붙이느냐의 여부에따라 오버로딩이 되는거다.
함수의 오버로딩
#include<iostream>
using std::cout;
using std::endl;
class test{
const int val;
public:
test(int _val):val(_val){
}
void print() const{
cout<<val<<endl;
}
void print(){
cout<<val<<endl;
}
};
int main(){
const test work1(10);
work1.print();
test work2(20);
work2.print();
return 0;
}
using std::cout;
using std::endl;
class test{
const int val;
public:
test(int _val):val(_val){
}
void print() const{
cout<<val<<endl;
}
void print(){
cout<<val<<endl;
}
};
int main(){
const test work1(10);
work1.print();
test work2(20);
work2.print();
return 0;
}
댓글을 달아 주세요
C언어에서 변수의 초기화는 대게 대입연산자를 통해서 했는데 c++로 넘어오면서 다른 방식이 생겼다.
C 초기화 스타일.
C++ 초기화 스타일.
C 초기화 스타일.
int num = 0;
C++ 초기화 스타일.
int num(0);
시작부터 왠 잡설 -ㅅ-? 하는데 이런 형식의 초기화를 사용하여 객체를 복사할수 있다.
미리 생성한 객체와 나중에 생성한 객체가 같은 값을 가지길 원한다면 아래와 같이 코딩해보쟈 ㅋㅋ
#include<iostream>
using std::cout;
using std::endl;
class test{
int x;
int y;
public:
test(int _x , int _y){ //생성자.
x = _x;
y = _y;
}
test(test & copy){ //복사 생성자.
x = copy.x;
y = copy.y;
}
void print(){
cout<<"x = "<<x<<endl
<<"y = "<<y<<endl;
}
};
int main(){
test p1(5,10);
p1.print();
test p2(p1);
p2.print();
return 0;
}
using std::cout;
using std::endl;
class test{
int x;
int y;
public:
test(int _x , int _y){ //생성자.
x = _x;
y = _y;
}
test(test & copy){ //복사 생성자.
x = copy.x;
y = copy.y;
}
void print(){
cout<<"x = "<<x<<endl
<<"y = "<<y<<endl;
}
};
int main(){
test p1(5,10);
p1.print();
test p2(p1);
p2.print();
return 0;
}
c-b-r에 대해 배웠다면 무슨의미인지 눈에 확연히 들어올거다. 중요한건 레퍼런스에 의해 주소값이 복사된 객체의 맴버데이터를 생성자에서 대입하고 있는것이다. 이렇게 맴버데이터별 대입을 하면 이전 객체와 나중 객체가 같은 값을 갖게된다. 물론 주소는 다르겟지만;
잡설:컴파일러는 클래스 내에서 생성자또는 소멸자가 없을경우 디폴트 생성자와 소멸자를 자동으로 제공해준다. 그렇다면 복사 생성자도 마찬가질까?... ㅇㅅㅇ 마찬가지다 ㅋ
#include<iostream>
using std::cout;
using std::endl;
class test{
int x;
int y;
public:
test(int _x , int _y){ //생성자.
x = _x;
y = _y;
}
void print(){
cout<<"x = "<<x<<endl
<<"y = "<<y<<endl;
}
};
int main(){
test p1(5,10);
p1.print();
test p2(p1);
p2.print();
return 0;
}
using std::cout;
using std::endl;
class test{
int x;
int y;
public:
test(int _x , int _y){ //생성자.
x = _x;
y = _y;
}
void print(){
cout<<"x = "<<x<<endl
<<"y = "<<y<<endl;
}
};
int main(){
test p1(5,10);
p1.print();
test p2(p1);
p2.print();
return 0;
}

댓글을 달아 주세요
제피트할아버지는 피노키오를 소유한다.
피노키오는 큰코를 소유한다.
제피트할아버지는 큰 코를가진 피노키오를 소유하므로
이중상속인가요?