개발/C++

11장 포인터와 동적 메모리 관리(후)

민돌이2 2019. 5. 9. 02:26

한성대학교 김설현교수님 강의내용을 바탕으로 작성함

 

동적 메모리 할당프로그램 실행 도중 필요한 만큼의 메모리를 할당하는 것이다.new연산자를 이용해 동적으로 메모리를 할당하며, heap에 저장된다.

int *p = new int;

 

new연산자를 사용해 할당한 메모리는 영구적이며, delete를 사용하여 제거하고 포인터변수에 NULL을 대입해야한다.

int *p = new int;
delte p;
p = NULL;

int *p = new int[size];
delete [ ] p;
p = NULL;

 

동적 객체 생성과 접근

아래의 구문을 사용하여 heap에 동적으로 객체 생성 가능하다.

Circle* cp = new Circle;
Circle* cp = new Circle(2);

포인터를 통한 객체 멤버에 접근하기 위해서는 점(.)이나 화살표(->)연산자를 사용한다.

cp->getRadius()
(*cp).getRadius()

 

this 포인터

객체 자신을 가리킨다.

set()함수나 매개변수 있는 생성자에서 종종 매개변수와 데이터필드에 같은 이름을 사용할 때 사용한다.

Circle::Circle(double radius)
{
	this->radius = radius; //this->radius 는 본래의 radius이고 오른쪽의 radius는 받는 값
}

 

소멸자

생성자의 반대이며 생성자와 동일한 이름을 갖지만 앞에(~)가 붙어야 한다.

기본적으로 모든 클래스에는 기본 소멸자가 포함된다.

사용자의 요구 동작을 수행하기 위해 구현하는 경우가 있다.

Circle.h 

 

#ifndef CIRCLE_H
#define CIRCLE_H

class Circle {
public:
	Circle();
	Circle(double);
	~Circle(); // 소멸자 
	double getArea();
	double getRadius();
	void setRadius(double);
	static int getNumberOfObjects();


private:
	double radius;
	static int numberOfObjects;
};
#endif

Circle.cpp

#include "Circle.h"

int Circle::numberOfObjects = 0; //정적멤버 초기화

Circle::Circle() 
{
	radius = 1;
	numberOfObjects++;
}

Circle::Circle(double radius) 
{
	this->radius = radius;
	numberOfObjects++;
}

Circle::~Circle() //소멸자
{  
	numberOfObjects--;
}

double Circle::getArea()
{
	return radius * radius * 3.14159;
}

double Circle::getRadius() 
{
	return radius;
}

void Circle::setRadius(double radius) 
{
	this->radius = (radius >= 0) ? radius : 0;
}

int Circle::getNumberOfObjects() 
{
	return numberOfObjects;
}

main.cpp

#incldue<iostream>
#include"Circle.h"
using namespace std;

int main() 
{
	Circle* pCircle1 = new Circle();
	Circle* pCircle2 = new Circle(5.0);
	Circle* pCircle3 = new Circle(2);

	cout << "원의 개수: " << Circle::getNumberOfObjects() << endl;
	delete pCircle1;
	pCircle1 = NULL;
	cout << "원의 개수: " << Circle::getNumberOfObjects() << endl;

	system("pause");
	return 0;
}

실행 결과

소멸자가 없었으면 삭제후에도 3이 나온다.

 

복사 생성자

동일 클래스의 다른 객체의 데이터를 초기화 된 객체를 생성하는데 사용한다.

Circle circle1 (5); 
Circle circle2 (circle1);
Circle circle3 = circle1;

Circle 클래스의 복사 생성자의 시그니쳐는 아래와 같다.

Circle (const Circle&)

복사생성자를 정의하지 않으면 기본 복사 생성자가 각 클래스에 제공된다.

기본 복사 생성자는 얕은 복사를 수행한다.

 

얕은 복사 vs 깊은 복사

얕은 복사 : 포인터의 주소가 복사된다.

깊은 복사 : 포인터의 내용이 복사된다.

즉, 얕은 복사를 하면 복사후 원본을 변경하면 복사본도 같이 변경된다.

 

얕은복사

Course.h

#ifndef CIRCLE_H
#define CIRCLE_H

class Course
{
public:
	Course(const string& courseName, int capacity);
	~Course();
	void addStudent(const string& name);
	string* getStudents() const;
	int getNumberOfStudents() const;

private:
	string courseName;
	string* students;
	int numberOfStudents;
	int capacity;
};
#endif

Course.cpp

#include "Course.h"

Course::Course(const string& courseName, int capacity)
{
	numberOfStudents = 0;
	this->courseName = courseName;
	this->capacity = capacity;
	students = new string[capacity];
}

Course::~Course() 
{
	//delete[] students; //얕은복사에서 에러
}

void Course::addStudent(const string& name) 
{
	students[numberOfStudents] = name;
	numberOfStudents++;
}

string* Course::getStudents() const 
{
	return students;
}

int Course::getNumberOfStudents() const 
{
	return numberOfStudents;
}

main.cpp

#include <iostream>
#include "Course.h"
using namespace std;

int main() 
{
	Course course1("C++ Programming", 10);
	Course course2(course1);

	course1.addStudent("Peter Pan"); // Add a student to course1
	course2.addStudent("Lisa Ma"); // Add a student to course2

	cout << "students in course1: " << course1.getStudents()[0] << endl;
	cout << "students in course2: " << course2.getStudents()[0] << endl;

	system("pause");
	return 0;
}

실행 결과

 

깊은복사

Course.h

#ifndef CIRCLE_H
#define CIRCLE_H

class Course 
{
public:
	Course(const string& courseName, int capacity);
	~Course();
	Course(const Course&); //복사생성자 

	void addStudent(const string& name);
	string* getStudents() const;
	int getNumberOfStudents() const;

private:
	string courseName;
	string* students;
	int numberOfStudents;
	int capacity;
};
#endif

Course.cpp

#include "Course.h"

Course::Course(const string& courseName, int capacity)
{
	numberOfStudents = 0;
	this->courseName = courseName;
	this->capacity = capacity;
	students = new string[capacity];
} 

Course::~Course() 
{
	delete[] students; //에러안남
}

//복사생성자
Course::Course(const Course& course)
{
	courseName = course.courseName;
	numberOfStudents = course.numberOfStudents;
	capacity = course.capacity;
	students = new string[capacity];

	for (int i = 0; i < numberOfStudents; i++)
		students[i] = course.students[i];
}
void Course::addStudent(const string& name) 
{
	students[numberOfStudents] = name;
	numberOfStudents++;
}

string* Course::getStudents() const 
{
	return students;
}

int Course::getNumberOfStudents() const 
{
	return numberOfStudents;
}

main.cpp

#include <iostream>
#include "Course.h"
using namespace std;

int main() 
{
	Course course1("C++ Programming", 10);
	Course course2(course1);

	course1.addStudent("Peter Pan"); // Add a student to course1
	course2.addStudent("Lisa Ma"); // Add a student to course2

	cout << "students in course1: " << course1.getStudents()[0] << endl;
	cout << "students in course2: " << course2.getStudents()[0] << endl;

	system("pause");
	return 0;
}

실행 결과

728x90