C++

9주차 강의내용

wlsn 2024. 10. 29. 13:50

캡슐화와 재사용이 가능한 범위를 알려주는 사진이다. 파란색 부분이 재사용이 가능한 부분

 

객체가 일반,포인터일 경우 "."과 "->"을 쓴다.

 

기말고사에 이와 비슷한 문제가 출제됨

 

#include <iostream> // 입출력 스트림 라이브러리 포함
using namespace std; // std 네임스페이스 사용
// Dog 클래스 정의
class Dog {
private:
int age; // 개의 나이
double weight; // 개의 체중
string name; // 개의 이름
public:
// 나이를 반환하는 메서드
int getAge() {
return age; // age 변수의 값을 반환
}
 
// 나이를 설정하는 메서드
void setAge(int a) {
age = a; // 매개변수 a를 age 변수에 저장
}
 
// 체중을 반환하는 메서드
double getWeight() {
return weight; // weight 변수의 값을 반환
}
 
// 체중을 설정하는 메서드
void setWeight(double w) {
weight = w; // 매개변수 w를 weight 변수에 저장
}
 
// 이름을 반환하는 메서드
string getName() {
return name; // name 변수의 값을 반환
}
 
// 이름을 설정하는 메서드
void setName(string n) {
name = n; // 매개변수 n을 name 변수에 저장
}
};
// 메인 함수
int main() {
Dog happy; // Dog 클래스의 인스턴스 happy 생성
happy.setAge(3); // happy의 나이를 3으로 설정
happy.setWeight(3.5); // happy의 체중을 3.5로 설정
happy.setName("해피"); // happy의 이름을 "해피"로 설정
 
// happy의 정보를 출력
cout << happy.getName() << "는 "
<< happy.getAge() << "살, "
<< happy.getWeight() << "kg입니다.\n";
 
return 0; // 프로그램 종료
}

ai에게 주석을 달아달라고 했을때의 답이다.

 

#include <iostream>
using namespace std;
// Dog 클래스 정의
class Dog {
private:
int age; // 개의 나이
double weight; // 개의 체중
string name; // 개의 이름
public:
// 생성자: 초기값을 설정할 수 있도록
Dog(string n, int a, double w) {
setName(n);
setAge(a);
setWeight(w);
}
// 나이를 반환하는 메서드 (const)
int getAge() const {
return age;
}
 
// 나이를 설정하는 메서드
void setAge(int a) {
if (a >= 0) { // 나이가 유효한 값인지 검사
age = a;
} else {
cout << "유효하지 않은 나이입니다.\n"; // 오류 메시지
}
}
 
// 체중을 반환하는 메서드 (const)
double getWeight() const {
return weight;
}
 
// 체중을 설정하는 메서드
void setWeight(double w) {
if (w >= 0) { // 체중이 유효한 값인지 검사
weight = w;
} else {
cout << "유효하지 않은 체중입니다.\n"; // 오류 메시지
}
}
 
// 이름을 반환하는 메서드 (const)
string getName() const {
return name;
}
 
// 이름을 설정하는 메서드
void setName(string n) {
name = n; // 이름은 빈 문자열을 허용
}
};
// 메인 함수
int main() {
// Dog 객체를 생성하면서 초기값을 설정
Dog happy("해피", 3, 3.5);
 
// happy의 정보를 출력
cout << happy.getName() << "는 "
<< happy.getAge() << "살, "
<< happy.getWeight() << "kg입니다.\n";
 
return 0; // 프로그램 종료
}

모자른 부분을 보완해달라고 했을때의 답. 나이나 체중이 마이너스일리는 없으니까 말이다.

 

많이 사용하는 문자열 관련 함수다. 1번과 4번이 제일 중요하다.

그냥 st1 = st2를 한다면 한가지밖에 복사가 안되지만 strcpy(st1, st2)를 사용한다면 두 변수가 같다고 정의할 수 있다.

 

배열에 문자열을 넣을때 null문자가 자동으로 들어가게 된다. 위 사진은 그걸 시각화해서 보여주는 것

 

10번째 줄로갔을때 s1이 strcpy를 통해 s2를 복사해 s2와 똑같이 되었다. null문자도 동일하게 복사한 모습.

 

왼쪽에 있는 소스는 C이고, 오른쪽은 C++ 소스다. C언어는 strcpy를 써 복사하지만, C++은 s1 = s2로 대입을 시켜 끝낸다.

 

char배열은 성능과 메모리제어가 중요할때 사용한다.

하지만 버퍼 오버플로우와같은 메모리 안전성에 취약하고 문자열 조작 기능이 없어 수동으로 처리해야하는 단점이있다.

 

std::string은 안전하고 편리하다.

메모리 할당과 해제를 자동으로 관리하므로 char배열에 비해 성능이 조금 떨어지고, 문자열의 길이도 저장하므로 메모리 사용한이 더 많다. 그래도 char형보다는 99% 상황에서 더 유용하니 std::string형이 매우 우세하다.

 

const char와 string의 차이를 보여주는 사진이다.

 

#include <iostream>
using std::cout;
class Dog{
private:
int age;
public:
int getAge(){return age;} //자동 inline함수
void setAge(int a){age=a;} //자동 inline함수
};
int main()
{
int i;
Dog dd[5]; //Dog클래스형 객체배열 dd, 강아지 5마리
for(i=0;i<5;i++){
dd[i].setAge(i);
cout<<dd[i].getAge(); //01234
}
return 0;
}
와 같이쓴다면 값은 01234가 출력된다.
하지만 dd[i].setAge(i)부분에 i를 1로 바꾼다면 모두 1로 시작하기때문에 11111이 출력된다.

생성자와 소멸자는 각각 생성되고, 소멸할때 자동으로 호출된다. 이는 생성 소멸 이외에는 불러올 수 없다.

생성자와 소멸자는 써도되고, 안써도 상관없다.

 

객체를 초기화할때 생성자를 사용한다.

생성자는 멤버에 대한 초기화자료를 지정해주지 않는다면 쓰레기값을 갖는다.

 

#include <iostream>
using std::cout;
class Dog {
private:
int age = 1; //C++11부터 가능
public:
int getAge();
void setAge(int a);
};
int Dog::getAge()
{
return age;
}
void Dog::setAge(int a)
{
age = a;
}
int main()
{
Dog happy, coco;
cout << happy.getAge() << coco.getAge();
return 0;
}

void setAge나 main이 들어가기전에 생성자가 들어갈 수 있다.

 

생성자의 가장 큰 특징은 리턴값이 존재하지 않으며 void형을 지정하지 않아도 되는 것이다.

그 외로 클래스명과 생성자명이 같고, 자동호출된다.

 

프로그래밍 언어에서 implicit가 나온다면 "항상 자동"이라는 뜻도 지닌다.

 

Dog를 불러오지 않았음에도 생성자 정의로 age=1로 지정했기때문에 1로 바뀐다.

 

#include <iostream>
using std::cout;
class Dog {
private:
int age;
public:
// Dog() { age = 1; } // 생성자 정의,
// Dog():age(1){ }
Dog():age{1}{ }
int getAge() { return age; }
void setAge(int a) { age = a; }
};
int main()
{
Dog happy; //happy객체가 생성되는 순간 생성자가 자동 호출됨
cout << happy.getAge();
return 0;
}
public부분에 Dog부분에 주석친 부분은 모두 같은 실행결과를 나타낸다.
 

C++언어에서 변수를 초기화하는 방법이다. (),{}가 더 나을 수 있다. 평범한 상황에서는 1번이 제일 좋을 수 있다.

기말고사에 꼭 나오는 부분이다.

 

클래스의 멤버변수 초기화 방법중 첫번째 방법이 일반적이지만 두번째 방법이 조금 더 나을 수 있다. 세번째 방법은 여러가지 변수를 한번에 초기화 할 때 쓰는 방법이다.

 

나이를 직접 입력해 바꿔줄 수 있다. initializer는 기말고사에 무조건 출제되는 문제이니 꼭 알아두도록 하자.

 

1번 방법을 복사초기화

2번 방법을 다이렉트초기화라고 부른다.

 

char* 처럼 포인터를 쓸 경우 5가지 멤버변수를 써줘야하기때문에 초보자들은 사용하지 않는게 좋다.

 

객체가 생성될때 생성자가 호출되고 사라질때 소멸자가 나오지만 오랫동안 남는다.

 

#include <iostream>
using std::cout;
class Dog {
private:
int age;
public:
Dog(int a) { age = a; }
~Dog() { cout << "소멸"; }
int getAge();
void setAge(int a);
}; int Dog::getAge()
{
return age;
}
void Dog::setAge(int a) {age = a;} //멤버변수age=매개변수age
int main()
{
Dog happy(5);
cout << happy.getAge();
return 0;
}

와 같이 쓸 수도 있지만,

#include <iostream>
using std::cout;
class Dog {
private:
int age;
public:
Dog(int age) {this->age = age;}
~Dog() { cout << "소멸"; }
int getAge();
void setAge(int a);
}; int Dog::getAge()
{
return age;
}
void Dog::setAge(int age) {this->age = age;} //멤버변수age=매개변수age
int main()
{
Dog happy(5);
cout << happy.getAge();
return 0;
}
일반적으로 this를 써서 만들 수 있다.
#include <iostream>
using std::cout;
class Cat {
private:
int age;
public:
int getAge() {return age;}
void setAge(int a) {age = a;}
};
int main()
{
Cat ya;
ya.setAge(1);
cout << ya.getAge();
return 0;
}
1단계의 모습
출력결과는 1이 출력됨.
#include <iostream>
using std::cout;
class Cat {
private:
int age;
public:
Cat() { //생성자
age = 1;
}
int getAge() {return age;}
void setAge(int a) {age = a;}
};
int main()
{
Cat ya;
cout << ya.getAge() << std::endl;
ya.setAge(2);
cout << ya.getAge();
return 0;
}
2단계의 모습. 기본적인 생성자 추가
 
출력 결과는 1,2가 출력됨.
 
#include <iostream>
using std::cout;
class Cat {
private:
int age;
public:
Cat() { //생성자
age = 1;
}
~Cat() { //소멸자
cout << "야옹~~\n";
}
int getAge() {return age;}
void setAge(int a) {age = a;}
};
int main()
{
Cat ya;
cout << ya.getAge() << std::endl;
ya.setAge(2);
cout << ya.getAge();
return 0;
}
3단계의 모습. 기본적인 소멸자 추가
 
출력 결과는 1,2야옹~~이 출력됨.
 
#include <iostream>
using std::cout;
class Cat {
private:
int age;
public:
Cat(int a) { //생성자
age = a;
}
~Cat() { //소멸자
cout << "야옹~~\n";
}
int getAge() {return age;}
void setAge(int a) {age = a;}
};
int main()
{
Cat ya(1);
cout << ya.getAge() << std::endl;
ya.setAge(2);
cout << ya.getAge();
return 0;
}
4단계의 모습. 생성자의 매개변수를 추가하고 main부분에 ya -> ya(1)로 변경
 
#include <iostream>
using std::cout;
class Cat {
private:
int age;
public:
Cat(int age) { //생성자
this->age = age;
}
~Cat() { //소멸자
cout << "야옹~~\n";
}
int getAge() {return age;}
void setAge(int age) {this->age = age;}
};
int main()
{
Cat ya(1);
cout << ya.getAge() << std::endl;
ya.setAge(2);
cout << ya.getAge();
return 0;
}
5단계의 모습. this 포인터를 추가하기 위해 생성자와 void부분에 age = a부분을 this->age=age로 변경.
 
#include <iostream>
using std::cout;
class Cat {
private:
int age;
std::string name;
public:
Cat(std::string name, int age) { //생성자
this->age = age;
this->name = name;
}
~Cat() { //소멸자
cout << "야옹~~\n";
}
int getAge() { return age; }
void setAge(int age) { this->age = age; }
std::string getName() { return name; }
void setName(int age) { this->name = name; }
};
int main()
{
Cat ya("야옹이",1);
cout << ya.getName() << ya.getAge() << std::endl;
ya.setAge(2);
cout << ya.getName() << ya.getAge() << std::endl;
return 0;
}
마지막 6단계 모습. getName을 지정과 동시에 생성자 부분에 추가. 
 
출력 결과는 야옹이1,야옹이2,야옹~~이 출력됨.

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

10주차 강의 내용  (0) 2024.11.05
10주차 예습과제  (0) 2024.11.04
9주차 예습과제  (0) 2024.10.29
7주차 강의 내용  (0) 2024.10.15
C++ 7주차 예습과제  (0) 2024.10.14