c++programmingc++ programming · 2014-10-04 · c++ c++...
TRANSCRIPT
C++ ProgrammingC++ ProgrammingC++ ProgrammingC++ ProgrammingC++ ProgrammingC++ ProgrammingC++ ProgrammingC++ Programming
C C 언어에서언어에서 C++ C++ 언어로의언어로의 전환전환C C 언어에서언어에서 C++ C++ 언어로의언어로의 전환전환
SeoSeo, Doo, Doo--okok
[email protected]@gmail.comhttp://www.Clickseo.comhttp://www.Clickseo.com
목목 차차
C++ C++ 언어언어 개요개요CC 언어언어 개요개요
C C 언어언어 기반의기반의 C++C++
2
C++ C++ 언어언어 개요개요
C++ C++ 언어언어 개요개요
C++ C++ 언어의언어의 역사역사 및및 특징특징
통합통합 개발개발 환경환경통합통합 개발개발 환경환경
C C 언어언어 기반의기반의 C++C++
3
C++ C++ 언어의언어의 역사역사 및및 특징특징징징
C++ 언어의 역사
1979년, C with Classes• AT&T 벨 연구소의 비야네 스트롭스트룹(Bjarne Stroustrup)에 의하여 개발
• 객체지향성이 더해진 C 언어의 확장형
• 클래스 개념과 엄격한 데이터 확인
인라인(inlining) 그리고 디폴트 인자(default argument)• 인라인(inlining) 그리고 디폴트 인자(default argument)
• Cfront : 최초의 C++ 컴파일러
1983년, C++ 로 이름을 변경하여 발표
• 가상 함수(virtual functions)
• 함수와 연산자 오버로딩(function name and operator overloading)• 함수와 연산자 오버로딩(function name and operator overloading)
• 단일 라인 주석 : // (two forward slashes)
4
C++ C++ 언어의언어의 역사역사 및및 특징특징 (cont(cont’’d)d)징징
C++ 언어의 역사 (cont’d)
1989년, C++ 2.0
• 다중 상속 (multiple inheritance)
• 추상 클래스 (abstract classes)
• 동적 멤버 함수 (static member functions)
• 상수 멤버 함수 (const member functions)
보호된 멤버 (protected members)• 보호된 멤버 (protected members)
1990년, The Annotated C++ Reference Manual
• 템플릿 (templates)
• 예외 처리 (exception handling)
• 네임스페이스 (namespace)• 네임스페이스 (namespace)
• 새로운 형 변환 (new casts)
• 부울형 (Boolenan type)
5
C++ C++ 언어의언어의 역사역사 및및 특징특징 (cont(cont’’d)d)징징
C++ 언어의 표준화 과정
1998년, C++98 : ISO/IEC 14882:1998
2003년, C++03 : ISO/IEC 14882:2003
2005년 TR1 (Lib T h i l R 1) 2005년, TR1 (Library Technical Report 1)
• 오늘날 대부분의 C++ 컴파일러에서 지원
C++0x : ISO/IEC JTC1/SC22/WG21 C++ 표준화 위원회
• C++ 프로그래밍 언어를 위한 새로운 버전의 비공식적인 명칭
• TR1 라이브러리를 포함하여 C++ 표준 라이브러리를 확장
• 2010년 03월, 최신 드레프트(draft) 문서 발표 : N3092
• 2011년 말에 표준 완료 후 발표 예정
• C++0x 표준안이 완료된 이후에 TR2를 계획
6
통합통합 개발개발 환경환경통통 경경
통합 개발 환경
IDE (I d D l E i ) IDE (Integrated Development Environment)
• 코딩, 디버그, 컴파일, 배포 등 프로그램 개발에 관련된 모든 작업을 하나의 프로그램
안에서 처리하는 환경을 제공하는 소프트웨어
래의 웨어 개발에서는 컴파일러 텍 편집기 디버거 을 따• 종래의 소프트웨어 개발에서는 컴파일러, 텍스트 편집기, 디버거 등을 따로
사용했다.
Microsoft Visual C++ 6.0 : 상업용
Visual Studio Express• Free Software• Free Software
• http://www.microsoft.com/express/
D C Dev-C++
• Free Software(GNU GPL), Open Source
• http://www.bloodshed.net/dev/
7
C C 언어언어 기반의기반의 C++C++
C++ C++ 언어언어 개요개요
C C 언어언어 기반의기반의 C++C++
C++ C++ 스타일의스타일의 입출력입출력
데이터데이터 형과형과 변수변수
배열배열, , 문자열문자열, , 구조체구조체
C++C++ 스타일의스타일의 함수함수 C++ C++ 스타일의스타일의 함수함수
네임스페이스네임스페이스
참참 조조
동적동적 메모리메모리 할당할당
8
C++ C++ 스타일의스타일의 입출력입출력
간단한 C++ 프로그램 구조 : 과거 스타일
/*
간단한 C++ 프로그램 구조
작성자 : 서두옥
과거 스타일!!!
작성자 : 서두옥
콘솔 출력(Console Output) : cout
*/
#include <iostream.h>
int main(void)
{
cout << "Hello World!” << endl;cout << Hello World! << endl;
return 0;
9
}
C++ C++ 스타일의스타일의 입출력입출력 (cont(cont’’d)d)
간단한 C++ 프로그램 구조 : 현재 스타일
/*
간단한 C++ 프로그램 구조
작성자 : 서두옥
현재 스타일!!!
*/
#i l d <iostream>#include <iostream>
int main(void)
{
std::cout << "Hello World! \n" << std::flush;std::cout << "Hello World!" << std::endl;
return 0;
}
10
}
C++ C++ 스타일의스타일의 입출력입출력 (cont(cont’’d)d)
프로그램 예제 : 다양한 데이터 출력
#include <iostream>#include <iostream>
int main(void){
char ch = 'A';int i = 10;double d = 10.12345;
std::cout << "ch : " << ch << std::endl;std::cout << "i : " << i << std::endl;std::cout << "d : " << d << std::endl;
std::cout << "정수형 상수 : " << 10 << std::endl;std::cout << "실수형 상수" << " : " << 3.14 << std::endl;std::cout << "문자형 상수 : " << 'A' << std::endl;std::cout << "문자열 상수 : " << "Hello World!!!" << std::endl;
return 0;}
11
}
C++ C++ 스타일의스타일의 입출력입출력 (cont(cont’’d)d)
프로그램 예제 : 데이터 입력 및 출력
#include <iostream>
int main(void)
{
int a, b, res;
std::cout << "두 정수 입력 : " ;
std::cin >> a >> b;
res = a + b;
std::cout << a << " + " << b << " = " << res << std::endl;;
return 0;
}
12
}
데이터데이터 형과형과 변수변수형형
새로운 형태의 자료형 : bool
수 수 bool형 변수의 상태는 true와 false 둘 중 하나가 될 수 있다.
#include <iostream>
int main(void)
{{
std::cout << true << std::endl;
std::cout << false << std::endl;
return 0;
}
13
데이터데이터 형과형과 변수변수 (cont(cont’’d)d)형형프로그램 예제 : 새로운 자료형 -- bool
#include <iostream>
int main(void)
{
bool state = false;
if(state == true)std::cout << "참!!!" << std::endl;
else
std::cout << "거짓!!!" << std::endl;
return 0;
}
14
데이터데이터 형과형과 변수변수 (cont(cont’’d)d)형형
변수 (variable)
변수 이름의 길이에는 제한이 없다 변수 이름의 길이에는 제한이 없다.
• C 에서 변수 이름의 길이 제한 : 63번째 문자까지만 인식
“지역 변수 선언의 위치 제한이 없다 ” 지역 변수 선언의 위치 제한이 없다.
#include <iostream>
int main(void){
int i = 100;
std::cout << i << std::endl;
int j = 200;
std::cout << j << std::endl;
return 0;
15
}
데이터데이터 형과형과 변수변수 (cont(cont’’d)d)형형프로그램 예제 : 제한 없는 지역 변수의 선언
#include <iostream>
int main(void)
{
int num;
std::cout << "원하는 단 : ";
std::cin >> num;
for( int i = 1; i<10; i++)
std::cout << num << " * " << i << " = " << num * i << std::endl;
return 0;
}
16
}
데이터데이터 형과형과 변수변수 (cont(cont’’d)d)형형
명시적 형 변환 (explicit type conversion)
t 수식 연산자( t i t ) cast 수식 연산자(cast expression operator)
• 임의로 어떤 형식에서 다른 형식으로 데이터를 변환시킨다.
#include <iostream>
int main(void){
i iint i;double d = 3.14159;
// i = (int)d;// i (int)d;i = int(d); // C++ 에서만 가능
std::cout << "i : " << i << std::endl;std::cout << "d : " << d << std::endl;
return 0;}
17
}
배열배열, , 문자열문자열, , 구조체구조체,, ,,
C 언어 스타일의 문자열 (string)
C++ 에서 제공하는 문자열 조작 함수를 사용 : <cstring> C++ 에서 제공하는 문자열 조작 함수를 사용 : <cstring>
#include <iostream>#include <cstring>
int main(void){
char str[] = "Hi~ Clickseo!!!";char str[] Hi Clickseo!!! ;char copy[1024];int len = strlen(str);
t ( t )strcpy(copy, str);
std::cout << "길이 : " << len << std::endl;std::cout << "str : " << str << std::endl;std::cout << "copy : " << copy << std::endl;
return 0;}
18
}
배열배열, , 문자열문자열, , 구조체구조체 (cont(cont’’d)d),, ,,
구조체 (structure)
C 에서는 구조체의 태그 가 곧 자료형이다 C++ 에서는 구조체의 태그(tag)가 곧 자료형이다.
#include <iostream>
struct _score{
char name[12];int kor, eng, math, tot;float ave;
};
int main(void){
score temp;_score temp;
return 0;}
19
배열배열, , 문자열문자열, , 구조체구조체 (cont(cont’’d)d),, ,,프로그램 예제 : 구조체의 태그를 이용한 자료형
#include <iostream>#include <iostream>
struct _score{
char name[12];int kor, eng, math, tot;int kor, eng, math, tot;float ave;
};
int main(void){{
_score temp;
std::cout << "이름 : "; std::cin >> temp.name;std::cout << "국어 : "; std::cin >> temp.kor;std::cout << "영어 : "; std::cin >> temp.eng;std::cout << 영어 : ; std::cin >> temp.eng;std::cout << "수학 : "; std::cin >> temp.math;
temp.tot = temp.kor + temp.eng + temp.math;temp.ave = float(temp.tot)/3;
std::cout << "\n ### 출력 결과 ###" << std::endl;std::cout << temp.name << " " << temp.kor << " " << temp.eng << " "
<< temp.math << " " << temp.tot << " " << temp.ave << std::endl;
return 0;
20
return 0;}
C++ C++ 스타일의스타일의 함수함수
함수 다중 정의 (Function Overloading)
C++ 에서 함수들이 동일한 이름을 사용할 수 있는 기능 C++ 에서 함수들이 동일한 이름을 사용할 수 있는 기능
• 단, 인자의 종류(매개 변수의 자료형이나 개수)는 달라야 한다.
int ADD(int, int);d bl ADD(d bl d bl )double ADD(double, double);
int main(void){
ADD(10, 20);ADD(10, 20);ADD(10.5, 20.5);
return 0;}
int ADD(int a, int b){
return a + b;}}
double ADD(double a, double b){
return a + b;
21
}
C++ C++ 스타일의스타일의 함수함수 (cont(cont’’d)d)
디폴트 인자 (Default Arguments)
따로 값을 지정해주지 않은 경우에 선택하는 인자의 값 따로 값을 지정해주지 않은 경우에 선택하는 인자의 값
• 함수 호출 시 적당한 값을 모르는 경우에 사용
• 매번 함수를 호출할 때마다 똑같은 인자의 값을 적어주는 것을 피하는 용도로 사용
• 디폴트 인자의 제한 : 디폴트 인자는 오른쪽 끝에 모여 있어야 한다.
#include <iostream>
int ADD(int int = 0);int ADD(int, int = 0);
int main(void){
std::cout << ADD(10) << std::endl;( )std::cout << ADD(10, 20) << std::endl;
return 0;}
int ADD(int a, int b){
return a + b;}
22
}
C++ C++ 스타일의스타일의 함수함수 (cont(cont’’d)d)
함수 오버로딩 vs. 디폴트 인자
#include <iostream>
int ADD(int a);int ADD(int a, int b = 0);( , );
int main(void){
std::cout << ADD(10) << std::endl; // error( )
return 0;}
int ADD(int a){
return a;}
int ADD(int a, int b){
return a + b;
23
}
C++ C++ 스타일의스타일의 함수함수 (cont(cont’’d)d)
C 언어 스타일의 in-line 화 : 매크로 함수
프로그램을 컴파일 하기 전에 전처리기에 의해 정의된 코드로 치환
#define ADD(a, b) ((a) + (b)) #define ADD(a, b) ((a) + (b))( , ) (( ) ( ))
int main(void)
{
( , ) (( ) ( ))
int main(void)
{{
int sum;
{
int sum;
sum = ADD(10, 20);
return 0;
sum = (10) + (20);
return 0;
}
적용 전
}
적용 후preprocessing
24
적용 전 적용 후(macro expansion)
C++ C++ 스타일의스타일의 함수함수 (cont(cont’’d)d)
C++ 스타일의 in-line화 : 인-라인 함수 (in-line Function)
수 키워드 inline을 이용한 함수의 in-line화는 컴파일러에 의해 처리
#include <iostream>
컴파일러에 의해 처리inline int ADD(int, int);
int main(void){
컴파일러에 의해 처리
int sum;
sum = ADD(10, 20);
std::cout << "합계 : " << sum << std::endl;
return 0;}
inline int ADD(int a, int b){
return a + b;
25
}
네임스페이스네임스페이스
네임스페이스의 등장 배경
수 같은 이름의 함수를 포함하면 컴파일 시 문제 발생
#include <iostream>
void OUTPUT(void)void OUTPUT(void){
std::cout << "Hello World!!!" << std::endl;
return;}}
// error C2084: function 'void __cdecl OUTPUT(void)' already has a bodyvoid OUTPUT(void){
std::cout << "Hi~ Clickseo" << std::endl;std::cout << Hi Clickseo << std::endl;
return;}
int main(void)int main(void){
OUTPUT();
return 0;}
26
}
네임스페이스네임스페이스 (cont(cont’’d)d)
네임스페이스 (namespace)
특정 영역(공간)의 범위를 지정하고 이름을 붙여준 것 특정 영역(공간)의 범위를 지정하고 이름을 붙여준 것
#include <iostream>
namespace A{
“이름 공간이 다르면
같은 이름의 변수나 함수의 선언이 허용된다.”{void OUTPUT(void){
std::cout << "Hello World!!!" << std::endl;
return;}}
}
namespace B{
void OUTPUT(void){{
std::cout << "Hi~ Clickseo" << std::endl;
return;}
}}
int main(void){
A::OUTPUT();B::OUTPUT(); 범위 지정 연산자
(scope resolution operator)
27
return 0;}
(scope resolution operator)
네임스페이스네임스페이스 (cont(cont’’d)d)
네임스페이스에 별칭 부여
네임스페이스의 이름이 너무 긴 경우에는 간단한 별명을 붙여준 후에 네임스페이스의 이름이 너무 긴 경우에는 간단한 별명을 붙여준 후에,
그 별명을 대신 사용할 수 잇다.
#include <iostream>
using std::cout;using std::endl;
namespace Clickseo_namespace_data_temp{
int temp;}
namespace Click = Clickseo_namespace_data_temp;
int main(void){
cout << "temp : " << Click::temp << endl;
return 0;
28
}
네임스페이스네임스페이스 (cont(cont’’d)d)
프로그램 예제 : 중첩된 네임스페이스
#include <iostream>#include <iostream>
using std::cout;using std::endl;
namespace Clickseo{
namespace TEMP1{
int a = 10;int a = 10;}
namespace TEMP2{
int a = 20;}
}
int main(void)int main(void){
cout << "Clickseo::TEMP1::a : " << Clickseo::TEMP1::a << endl;cout << "Clickseo::TEMP2::a : " << Clickseo::TEMP2::a << endl;
29
return 0;}
네임스페이스네임스페이스 (cont(cont’’d)d)
이름 없는 네임스페이스
다른 파일에서 접근 제한
static 키워드를 사용한 전역 변수나 함수를
정의한 경우와 동일한 효과 다른 파일에서 접근 제한
#include <iostream>#include <iostream>
정의한 경우와 동일한 효과
using std::cout;using std::endl;
using std::cout;using std::endl;
extern void OUTPUT(void);
extern int temp;
namespace{
int temp = 10;}
int main(void){cout << "temp : " << temp << endl;
}
void OUTPUT(void){ p p
OUTPUT();
return 0;
cout << "temp : " << temp << endl;
return; 2.cpp1.cpp
30
}}pppp
네임스페이스네임스페이스 (cont(cont’’d)d)
분할 컴파일 namespace A { void OUTPUT(void); }namespace B { void OUTPUT(void); }
i t i ( id)int main(void){
A::OUTPUT();B::OUTPUT();
t 0 i#include <iostream>
namespace A{
void OUTPUT(void){
return 0;}
main.cpp
{std::cout << "Hello World!!!" << std::endl;
return;}
}1.cpp
}
#include <iostream>
namespace B{
id OUTPUT( id)void OUTPUT(void){
std::cout << "Hi~ Clickseo" << std::endl;
return;} 2.cpp
31
}}
pp
네임스페이스네임스페이스 (cont(cont’’d)d)
프로그램 예제 : 데이터 입출력
#i l d i t#include <iostream>
int main(void)
namespace std{
cout ???{
int temp;cin ???
endl ???
}std::cout << "정수 입력 : “;
std::cin >> temp;
}
std::cout << "temp : " << temp << std::endl;
return 0;
}
32
네임스페이스네임스페이스 (cont(cont’’d)d)
프로그램 예제 : 데이터 입출력 -- using
#i l d i t#include <iostream>
using std::cout;using std::cin; i dusing std::cin;using std::endl;
int main(void)
using namespace std;
int main(void)
{
int temp;
cout << "정수 입력 : “;
cin >> temp;
cout << “temp : " << temp << endl;
return 0;
33
}
네임스페이스네임스페이스 (cont(cont’’d)d)
프로그램 예제 : 지역변수와 전역변수
#i l d <i t >#include <iostream>
using std::cout;using std::endl;using std::endl;
int temp;
int main(void){
int temp = 10;
::temp++;
cout << "지역변수 : " << temp << endl;지역 수 p ;cout << "전역변수 : " << ::temp << endl;
return 0;
34
}
참참 조조
참조 (Reference)
이름이 존재하는 메모리 공간에 하나의 이름을 더 부여하는 행위 이름이 존재하는 메모리 공간에 하나의 이름을 더 부여하는 행위
• 참조는 일종의 별칭(alias)
• 만드는 방법 : 대상 개체의 형을 적고 참조 연산자(&)와 참조의 이름을 적으면 된다.
• 참조는 만드는 순간 초기화 되어야 한다 (단, 상수로 초기화 할 수는 없다).
int main(void)int main(void)
{
int a = 10;
1. 메모리 공간 할당
2. 이름 부여…
1001
1000
int *pa = &a;
int &ra = a;
1001
1002
1003
a 10
return 0;
}
1. 이름 하나 더 부여 …
1003
1004
35
}
참참 조조 (cont(cont’’d)d)
프로그램 예제 : 참조(reference)의 이해
#include <iostream>#include <iostream>
using std::cout;using std::endl;
int main(void){
int a = 10;int a 10;int &ra = a;
a++;t << “ " << << dlcout << “a : " << a << endl;
cout << "ra : " << ra << endl;
ra++;cout << “a : " << a << endl;cout << "ra : " << ra << endl;
return 0;
36
return 0;}
참참 조조 (cont(cont’’d)d)
참조에 의한 호출 (Call by reference)
#i l d <i t >#include <iostream>
using std::cout;using std::endl;
void SWAP(int & int &); 10 20
a b
void SWAP(int &, int &);
int main(void){
int a = 10, b = 20;
10 20
cout << "a : " << a << " , b : " << b << endl;SWAP(a, b);cout << "a : " << a << " , b : " << b << endl;
return 0;return 0;}
void SWAP(int &ra, int &rb){
int temp;int temp;
temp = ra;ra = rb;rb = temp;
}
37
}
참참 조조 (cont(cont’’d)d)
프로그램 예제 : 부담스러운 Call-by-value
#include <iostream> data#include <iostream>
using std::cout;using std::endl;
struct _score{
“서두옥” 70 80 90 240 70.0
data
{char name[12];int kor, eng, math, tot;float ave;
};
void OUTPUT( score); 서두옥”void OUTPUT(_score);int main(void){
_score data = {"서두옥", 70, 80, 90, 240, 80.0};
d
temp
“서두옥” 70 80 90 240 70.0
OUTPUT(data);return 0;
}
void OUTPUT( score temp)void OUTPUT(_score temp){
cout << "이름 : " << temp.name << endl;cout << "국어 : " << temp.kor << endl;cout << "영어 : " << temp.eng << endl;cout << "수학 : " << temp.math << endl;cout << "총점 : " << temp tot << endl;
38
cout << 총점 : << temp.tot << endl;cout << "평균 : " << temp.ave << endl;
}
참참 조조 (cont(cont’’d)d)
프로그램 예제 : Call-by-reference
#include <iostream>#include <iostream>
using std::cout;using std::endl;
struct _score{
“서두옥” 70 80 90 240 70.0
data{char name[12];int kor, eng, math, tot;float ave;
};
void OUTPUT(const score &);
data
void OUTPUT(const _score &);int main(void){
_score data = {"서두옥", 70, 80, 90, 240, 80.0};
dOUTPUT(data);return 0;
}
void OUTPUT(const score &temp) tempvoid OUTPUT(const _score &temp){
cout << "이름 : " << temp.name << endl;cout << "국어 : " << temp.kor << endl;cout << "영어 : " << temp.eng << endl;cout << "수학 : " << temp.math << endl;cout << "총점 : " << temp tot << endl;
temp
39
cout << 총점 : << temp.tot << endl;cout << "평균 : " << temp.ave << endl;
}
동적동적 메모리메모리 할당할당동동 당당
C 언어 스타일의 동적 메모리 할당
수 동적 메모리관리에 쓰이는 4가지 함수
• 표준 라이브러리 헤더 파일 <stdlib.h> 에서 찾을 수 있다.
• 메모리 할당 : malloc, calloc, realloc• 메모리 해제 : free
MemoryManagementManagement
malloc calloc realloc free
40
동적동적 메모리메모리 할당할당 (cont(cont’’d)d)동동 당당
C++ 스타일의 동적 메모리 할당 : new, delete 연산자
new 연산자 : 동적 메모리 할당
• 메모리 할당 실패 시 NULL 포인터 반환
int *p = new int; // 정수 하나를 저장할 메모리 할당
int *arr = new int[size]; // 정수를 size 개수만큼 저장할 메모리 할당
delete 연산자 : 동적 메모리 해제자 적 메 리 해제
delete p; // 할당된 메모리 공간 해제
delete []arr; // 할당된 메모리 공간이 배열일 경우delete []arr; // 할당된 메모리 공간이 배열일 경우
41
동적동적 메모리메모리 할당할당 (cont(cont’’d)d)동동 당당프로그램 예제 : 동적 메모리 할당
#include <iostream>#include <iostream>
using namespace std;
int main(void){
int i size;int i, size;
cout << "입력 할 학생 수 : ";cin >> size;
int *arr = new int[size];if( NULL)if(arr == NULL){
cout << "메모리 할당 실패!!! " << endl;return -1;
}
"\ ### 데이터 입력 ###"cout << "\n ### 데이터 입력 ###" << endl;for(i=0; i<size; i++){
cout << i << " : ";cin >> *(arr+i);
}}
cout << "\n ### 결과 출력 ###" << endl;for(i=0; i<size; i++)
cout << i << " : " << *(arr+i) << endl;
delete []arr;
42
delete []arr;return 0;
}
참고문헌참고문헌[1] 윤성우, “열혈강의 C++ 프로그래밍”, 프리렉, 2007.
[2] 이현창, “뇌를 자극하는 C++ 프로그래밍”, 한빛미디어, 2008.
[3] H M D it l P J D it l “C HOW TO PROGRAM 6th Editi P ti H ll 2009[3] H.M. Deitel, P. J. Deitel, “C++ HOW TO PROGRAM : 6th Edition”, Prentice Hall, 2009.
[4] 서두옥, 이동호(감수), “또 하나의 C : 프로그래밍은 셀프입니다”, 프리렉, 2011.
[5] Wikipedie, http://www.wikipedia.org/.
이 강의자료는 저작권법에 따라 보호받는 저작물이므로 무단 전제와 무단 복제를 금지하며,
내용의 전부 또는 일부를 이용하려면 반드시 저작권자의 서면 동의를 받아야 합니다.
C i ht © Cli k All i ht d
43
Copyright © Clickseo.com. All rights reserved.