C++ 프로그래밍

10주차_C++프로그래밍

기망지 2023. 11. 8. 12:32

✔️const 동적 메모리 할당 (new, delete)

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using std::cout;
class Cat {
private: //생략가능
	int age;
	char name[20];
	// const char* name; //A
public:
	Cat(int age, const char* n) {
		this->age = age;
		strcpy(name, n); // name=n; //A
		cout << name << "고양이 객체가 만들어졌어요.\n";
	}
	~Cat() { cout << name << "객체 바이\n"; };
	int getAge();
	const char* getName();
	void setAge(int age);
	void setName(const char* pName);
	void meow();
};
int Cat::getAge() {
	return age;
}
void Cat::setAge(int age) {
	this->age = age;
}
void Cat::setName(const char* pName) {
	strcpy(name, pName);
	//strcpy(대상주소, 원본주소);
	//strcpy_s(대상주소, 대상의길이, 원본주소);
	//name=pName; //A
}
const char* Cat::getName() {
	return name;
}
void Cat::meow() {
	cout << name << "고양이가 울어요\n";
}
int main() {
	Cat nabi(1, "나비"), yaong(1, "야옹"), * pNabi;
	cout << nabi.getName() << " 출생 나이는 " << nabi.getAge() << "살이다.\n";
	cout << yaong.getName() << " 출생 나이는 " << yaong.getAge() << "살이다.\n";
	pNabi = &nabi;
	cout << pNabi->getName() << " 출생 나이는 " << pNabi->getAge() << "살이다.\n";
	nabi.setName("Nabi");
	nabi.setAge(3);
	cout << nabi.getName() << " 나이는 " << nabi.getAge() << "살이다.\n";
	yaong.meow();
	nabi.meow();
	return 0;
}

const char* -> std::string으로 변경 / 배열로 쓰지 않고 string name으로 변경

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using std::cout;
class Cat {
private: //생략가능
	int age;
	std::string name;
public:
	Cat(int age, std::string n) {
		this->age = age;
		name=n;
		cout << name << "고양이 객체가 만들어졌어요.\n";
	}
	~Cat() { cout << name << "객체 바이\n"; };
	int getAge();
	std::string getName();
	void setAge(int age);
	void setName(std::string pName);
	void meow();
};
int Cat::getAge() {
	return age;
}
void Cat::setAge(int age) {
	this->age = age;
}
void Cat::setName(std::string pName) {
	name = pName;
	//strcpy(대상주소, 원본주소);
	//strcpy_s(대상주소, 대상의길이, 원본주소);
	//name=pName; //A
}
std::string Cat::getName() {
	return name;
}
void Cat::meow() {
	cout << name << "고양이가 울어요\n";
}
int main() {
	Cat nabi(1, "나비"), yaong(1, "야옹"), * pNabi;
	cout << nabi.getName() << " 출생 나이는 " << nabi.getAge() << "살이다.\n";
	cout << yaong.getName() << " 출생 나이는 " << yaong.getAge() << "살이다.\n";
	pNabi = &nabi;
	cout << pNabi->getName() << " 출생 나이는 " << pNabi->getAge() << "살이다.\n";
	nabi.setName("Nabi");
	nabi.setAge(3);
	cout << nabi.getName() << " 나이는 " << nabi.getAge() << "살이다.\n";
	yaong.meow();
	nabi.meow();
	return 0;
}

실행결과

const 변수

출처 : 한성현 교수님 ppt

const 변수 예제

#define IN 1 // 컴파일 전에 IN을 찾아서 1로 바꿈
#include <iostream>
int main()
{
	const int x = 2; // 변수 x는 항상 1, 변경 불가, 초기값 지정해야
	int const y = 3; // 비추, const는 자료형 앞에 씀
	const int z{ 4 }; // Uniform initialization, C++11, z{}
	constexpr int a = 5; //C++11부터 가능, compile-time constant
	//x = 2; //변경 불가
	//y = 10;
	//z = 20;
	std::cout << IN << x << y << z << a;
	return 0;
}

const키워드가 붙은 변수는 초기값을 지정하면 변경할 수 없다.

 

출처 : 한성현 교수님 ppt

멤버변수를 변경하지 않는 함수는 const를 뒤에 붙인다.

 

const형 멤버함수

#include <iostream>
class Dog {
	int age; //private 생략함
public:
	int getAge() const;
	void setAge(int a) { age = a; }
	void view() const
	{ 
		std::cout << "나는 view"; 
	}
};
int Dog::getAge() const
{
	view(); // 오류 ① : 7번째줄 - view를 const로 지정하면 오류 해결 / const함수는 const함수만 호출 가능, 일반 멤버함수 접근 불가
	return age; // 오류 ② : 멤버변수를 변경(++age:증가)했기 때문에 나는 오류
}
int main()
{
	Dog happy;
	happy.setAge(5);
	std::cout << happy.getAge();
	return 0;
}

const함수는 const함수만 호출할 수 있으며 일반 멤버함수에는 접근할 수 없다. 

: 일반 멤버함수에 접근하여 간접적으로 멤버변수를 변경하는 것을 막기 위해

const함수는 반드시 써야하는 것은 아니다. 그러나 쓰면 다른 사람들이 멤버변수를 변경할 수 없구나~라고 이해하는데 수월하다.

 

const 객체 예(오류 수정)

#include <iostream>
class Dog {
	int age;
public:
	Dog(int a) { age = a; }
	int getAge() const;
	void setAge(int a) { age = a; }
	void view() const
	{
		std::cout << "나는 view\n";
	}
};
int Dog::getAge() const
{
	view();
	return (age);
}
int main()
{
	const Dog happy(5); //const 객체
//	happy.setAge(7); // 오류
	std::cout << happy.getAge();
	return 0;
}

• Happy.setAge(7); 생략 -> 주석달아 실행시키지 않으면 오류가 안난다.

• const 객체 happy에는 const로 지정된 멤버함수만 호출할 수 있다.

• 해당 클래스의 어떠한 멤버변수도 바꾸지 않는 멤버함수(get으로 시작하는 함수)는 const형으로 선언하는 것이 좋다.

• 이렇게 하면 컴파일러가 오류를 찾는데 도움을 줄 수 있다.

 

정적 vs 동적 메모리 할당

출처 : 한성현 교수님 ppt

#include <iostream>
int main()
{
int array[1000000]; //4MB
std::cout << "aaaa";
return 0;
}//VS에서 실행될까?
//다른 컴파일러에서도 더 크게 잡으면
//exited, segmentation fault

지역변수는 스택에 저장하는데 기본 스택의 크기( Windows(Visual Studio)에서 기본 스택 크기는 1MB)를 넘어서 소스가 오류가 난다.

 

동적 메모리를 사용하는 3가지 이유

출처 : 한성현 교수님 ppt

 

하나의 정수에 대한 메모리 할당과 해제 : 정적 vs. 동적

#include <iostream>
int main()
{
	int *pi = new int; // 동적 메모리 할당 , heap
	int x; //정적 메모리 할당, 스택
	if (!pi) { // pi==0, 널 포인터인지 확인
		std::cout << "메모리할당이 되지 않았습니다.";
		return 1; //비정상 종료시 리턴값
	}
	*pi = 100; //주소의 값으로 100을 할당
	x = 10;
	std::cout << "동적메모리=" << *pi << ", x=" << x;
	delete pi; // 메모리 해제
	return 0; // 정상 종료시 리턴값
}

소스 4번째 줄 : 정수형 자료를 저장하기 위한 4바이트 공간할당. pi는 첫번째 공간의 주소

 

동적 메모리의 할당과 해제: new와 delete

출처 : 한성현 교수님 ppt

동적 메모리로 new를 썼으면 반드시 delete 써야한다.  안쓰면 다른 프로그램에서 사용이 불가하다.

배열을 해제할 때는 delete 뒤에 무조건 [](대괄호)를 붙여야한다.

 

파이썬 튜터 실행 결과

 

배열의 이름은 그 배열의 시작 주소(포인터)이다.

int x [3] = {1, 2, 3} 

x[0]; // 1

x[1]; // 2

x[2]; // 3

x는 1이 저장된 곳에 주소

x+1은 2가 저장된 곳에 주소

x+2는 3이 저장된 곳에 주소

 

객체 동적 할당

#include <iostream>
class Dog {
private:
	int age;
public:
	int getAge();
	void setAge(int a);
};
int Dog::getAge()
{
	return age;
}
void Dog::setAge(int a)
{
	age = a;
}
int main()
{
	Dog* dp;
	dp = new Dog; // Dog *dp=new Dog
	if (!dp) {
		std::cout << "메모리할당 불가!";
		return 1;
	}
	dp->setAge(5);
	std::cout << "메모리에 할당된 값은 "
		<< dp->getAge() << "입니다.";
	delete dp;
	return 0;
}

 

배열객체 동적 할당

#include <iostream>
class Dog {
private:
	int age;
public:
	int getAge();
	void setAge(int a);
};
int Dog::getAge()
{
	return age;
}
void Dog::setAge(int a)
{
	age = a;
}
int main()
{
	Dog* dp;
	dp = new Dog[10]; // 객체배열 할당
	// Dog *dp=new Dog[10];
	if (!dp) {
		std::cout << "메모리할당이 되지 않았습니다.";
		return 1;
	}
	for (int i = 0; i < 10; i++) // C++에서는 가능
		dp[i].setAge(i);
	for (int i = 0; i < 10; i++)
		std::cout << i << "번째 객체의 나이는 " <<
		dp[i].getAge() << " 입니다. " << std::endl;
	delete[]dp;
	return 0;
}

 

실습 과제

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using std::cout;
class Cat {
private: //생략가능
	int age;
	std::string name;
public:
	Cat(int age, std::string n) {
		this->age = age; 
		name = n;
		cout << name << "고양이 객체가 만들어졌어요.\n";
	}
	~Cat() { cout << name << "객체 바이\n"; };
	int getAge() const;
	std::string getName() const;
	void setAge(int age);
	void setName(std::string pName);
	void meow() const;
};
int Cat::getAge() const {
	return age;
}
void Cat::setAge(int age) {
	this->age = age;
}
void Cat::setName(std::string pName) {
	name = pName;
}
std::string Cat::getName() const {
	return name;
}
void Cat::meow() const {
	cout << name << "고양이가 울어요\n";
}
	int main() {
		Cat nabi(1, "나비"), yaong(1, "야옹"), * pNabi;
		cout << nabi.getName() << " 출생 나이는 " << nabi.getAge() << "살이다.\n";
		cout << yaong.getName() << " 출생 나이는 " << yaong.getAge() << "살이다.\n";
		pNabi = &nabi;
		cout << pNabi->getName() << " 출생 나이는 " << pNabi->getAge() << "살이다.\n";
		nabi.setName("Nabi");
		nabi.setAge(3);
		cout << nabi.getName() << " 나이는 " << nabi.getAge() << "살이다.\n";
		yaong.meow();
		nabi.meow();
		return 0;
	}