11.6 함수 호출에서 포인터 인수 전달
c++에서 함수의 매개변수로 값을 전달하는 방법과 참조를 통해 전달하는 방법을 배웠습니다. 이번에는 매개변수로 포인터를 받으면 어떻게 되는지 배워봅시다.
void func(int* p1)로 정의된 함수를 func(a1)으로 호출하면 p1과 a1은 같은 주소를 가리키는 두 포인터가 됩니다. 따라서 *p1값을 변경했을 때, p1과 a1이 가리키는 값은 변하지만 p1을 변경했을 때, a1이 가리키는 주소는 변하지 않기 때문에 a1의 값이나 주소가 변하지 않습니다.
void func(int* &p1)은 참조에 의한 포인터 인수의 전달입니다. 참조에 의해 전달되기 때문에 func(a1)을 했을 때, 주소를 전달할 수 없고 (주소를 저장하고 있는)포인터 변수만 전달할 수 있습니다. p1은 a1의 별명이 됩니다. p1과 a1은 동일하게 취급되기 때문에 둘 중 하나의 값을 바꿔도 다른 하나의 값이 바뀌고 주소를 바꿔도 둘 다 주소가 바뀝니다.
예제 ▼
#include <iostream>
using namespace std;
void swap1(int n1, int n2) {
int temp = n1;
n1 = n2;
n2 = temp;
}
void swap2(int& n1, int& n2) {
int temp = n1;
n1 = n2;
n2 = temp;
}
void swap3(int* n1, int* n2) {
int cnt = 6;
int temp = *n1;
*n1 = *n2;
*n2 = temp;
n1 = &cnt;
}
void swap4(int* &n1, int* &n2) {
int* temp = n1;
n1 = n2;
n2 = temp;
}
int main()
{
int num1 = 1;
int num2 = 2;
cout << "Before invoking the swap function,num1 is "
<< num1 << " and num2 is " << num2 << endl;
swap1(num1, num2);
cout << "After invoking the swap function,num1 is "
<< num1 << " and num2 is " << num2 << endl;
cout << endl;
num1 = 1;
num2 = 2;
cout << "Before invoking the swap function,num1 is "
<< num1 << " and num2 is " << num2 << endl;
swap2(num1, num2);
cout << "After invoking the swap function,num1 is "
<< num1 << " and num2 is " << num2 << endl;
cout << endl;
num1 = 1;
num2 = 2;
cout << "Before invoking the swap function,num1 is "
<< num1 << " and num2 is " << num2 << endl;
swap3(&num1, &num2);
cout << "After invoking the swap function,num1 is "
<< num1 << " and num2 is " << num2 << endl;
cout << endl;
num1 = 1;
num2 = 2;
int* p1 = &num1;
int* p2 = &num2;
cout << "Before invoking the swap function,num1 is "
<< num1 << " and num2 is " << num2 << endl;
swap3(&num1, &num2);
cout << "After invoking the swap function,num1 is "
<< num1 << " and num2 is " << num2 << endl;
cout << "Before invoking the swap function,p1 is "
<< p1 << " and p2 is " << p2 << endl;
swap4(p1, p2);
cout << "After invoking the swap function,p1 is "
<< p1 << " and p2 is " << p2 << endl;
cout << endl;
return 0;
}
함수에서 배열을 매개변수로 전달하는 것은 항상 포인터 인수를 전달하는 것으로 대체될 수 있습니다. 예를 들어, void m(int list[], int size)는 void m(int* list[], int size)로 변경할 수 있고, void m(char c_string[])은 void m(char* c_string[])으로 변경할 수 있습니다. 값이 변경되지 않는 경우, const로 매개변수를 설정해야 합니다.
#include <iostream>
using namespace std;
void printArray(const int* list , const int size){
for (int i = 0; i < size; i++) {
cout << list[i] << " ";
}
cout << endl;
}
int main()
{
const int SIZE = 6;
int list[SIZE] = { 11,12,13,14,15 ,16};
printArray(list, SIZE);
return 0;
}
checkpoint)
11.17) 다음 코드의 출력은 무엇인가?
#include <iostream>
using namespace std;
void f1(int x,int& y, int* z){
x++;
y++;
(*z)++;
}
int main()
{
int i = 1, j = 1, k = 1;
f1(i, j, &k);
cout << i << " " << j << " " << k << endl;
return 0;
}
//답
1 2 2
11.7) 함수로부터의 포인터 반환
함수의 반환값으로 포인터를 줄 수도 있습니다. 아래 예제의 reverse함수의 반환값의 유형은 int*입니다.
#include <iostream>
using namespace std;
void printArray(const int* list , const int size){
for (int i = 0; i < size; i++) {
cout << list[i] << " ";
}
cout << endl;
}
int* reverse(int* list, int size) {
for (int i = 0, j = size - 1; i < j;i++, j--) {
int temp = list[j];
list[j] = list[i];
list[i] = temp;
}
return list;
}
int main()
{
const int SIZE = 6;
int list[SIZE] = { 11,12,13,14,15,16 };
int* p = reverse(list, SIZE);
printArray(list, 6);
return 0;
}
//결과
16 15 14 13 12 11
checkpoint)
11.18) 다음 코드의 출력은 무엇인가?
#include <iostream>
using namespace std;
int* f(int list1[],const int list2[],int size) {
for (int i = 0; i < size; i++) {
list1[i] += list2[i];
}
return list1;
}
int main()
{
int list1[] = { 1,2,3,4 };
int list2[] = { 1,2,3,4 };
int* p = f(list1, list2, 4);
cout << p[0] << endl;
cout << p[1] << endl;
return 0;
}
//답
2
4
11.8) 유용한 배열 함수
#include <iostream>
#include <algorithm> //include
using namespace std;
void printArray(const int* list , const int size){
for (int i = 0; i < size; i++) {
cout << list[i] << " ";
}
cout << endl;
}
int main()
{
int list[] = { 4,2,3,6,5,1 };
printArray(list, 6);
//min_element
int* min = min_element(list, list + 6);
//max_element
int* max = max_element(list, list + 6);
cout << "The min value is " << *min << " at index "
<< (min - list) << endl;
cout << "The max value is " << *max << " at index "
<< (max - list) << endl;
//random_shuffle
random_shuffle(list, list + 6);
printArray(list, 6);
//sort
sort(list, list + 6);
printArray(list, 6);
//find
int key = 4;
int* p = find(list, list + 6, key);
if (p != list + 6)
cout << "The value " << *p << " is found at position "
<< (p - list) << endl;
else
cout << "The value " << *p << " is not found" << endl;
return 0;
}
//결과
4 2 3 6 5 1
The min value is 1 at index 5
The max value is 6 at index 3
5 2 6 3 4 1
1 2 3 4 5 6
The value 4 is found at position 3
checkpoint)
11.19)다음 코드의 출력은 무엇인가?
#include <iostream>
#include <algorithm>
using namespace std;
void printArray(const int* list , const int size){
for (int i = 0; i < size; i++) {
cout << list[i] << " ";
}
cout << endl;
}
int main()
{
int list[] = { 3,4,2,5,6,1 };
cout << *min_element(list, list + 2) << endl;
cout << *max_element(list,list+2) <<endl;
cout << *find(list,list+6,2)<<endl;
cout << find(list, list + 6, 20) <<endl;
sort(list, list + 6);
cout << list[5] <<endl;
return 0;
}
//결과
3
4
2
000000350B52F550
6
11.9) 동적 영구 메모리 할당
앞에 살펴봤던 reverse함수를 원래의 배열을 변경하지 않고 작성하려면 함수 안에 새로운 배열을 선언해야 합니다. 하지만 아래와 같이 실제로 새로운 배열을 함수 안에서 선언하면 함수가 끝날때, 지역변수인 새로운 배열이 반환되기 때문에 이상한 값이 반환됩니다. 따라서 함수가 반환된 후에도 함수 안의 배열에 접근할 수 있도록 영구 저장소에 저장해야 합니다. 그 방법으로 동적 메모리 할당에 대해 알아봅시다.
#include <iostream>
using namespace std;
void printArray(const int* list, const int size) {
for (int i = 0; i < size; i++) {
cout << list[i] << " ";
}
cout << endl;
}
int* reverse(const int* list, int size) {
int result[6];
for (int i = 0, j = size - 1; i < size; i++, j--) {
result[j] = list[i];
}
return result;
}
int main()
{
int list[] = { 1,2,3,4,5,6 };
int* p = reverse(list, 6);
printArray(p, 6);
return 0;
}
//출력
6 32761 1368412262 32759 -1108345912 76
c++에서 동적 메모리 할당은 new연산자로 할 수 있습니다. int* list = new int[size];
동적으로 할당된 메모리는 영국적이면 명시적으로 제거(delete)하거나 프로그램이 종료될 때까지 존재합니다.
#include <iostream>
using namespace std;
void printArray(const int* list , const int size){
for (int i = 0; i < size; i++) {
cout << list[i] << " ";
}
cout << endl;
}
int* reverse(const int* list, int size) {
int* result = new int[size];
for (int i = 0, j = size - 1; i < size; i++, j--) {
result[j] = list[i];
}
return result;
}
int main()
{
int list[] = { 1,2,3,4,5,6 };
int* p = reverse(list, 6);
printArray(p,6);
return 0;
}
//결과
6 5 4 3 2 1
new연산자에 의해 생성된 메모리를 명시적으로 삭제하기 위해서는 해당 포인터에 대해 delete연산자를 사용해야 합니다.
delete p;
또, new연산자에 의해 동적할당된 배열은 delete [] list; 로 삭제해야 합니다.
delete로 삭제된 메모리를 가리키는 모든 포인터는 정의되지 않은 상태가 되고 이를 허상포인터(dangling pointer)라고 합니다. 허상포인터에 대해서는 역참조 연산자(*)를 사용해서는 안됩니다. 또, new연산자에 의해 생성된 메모리를 가리키는 포인터만 delete로 삭제해야 합니다.
또, 어떤 포인터가 가리키고 있는, new연산자로 만든 메모리를 삭제하기 전에 그 포인터를 다시 new연산자로 초기화하면 원래 포인터가 가리키고 있던 메모리는 삭제할 수도 없고 접근할 수도 없게 됩니다. 이를 메모리 누설(memory leak)이라고 합니다.
int* p = new int;
*p = 45;
p = new int;
checkpoint)
11.20) double값에 대한 메모리 공간은 어떻게 생성하는 가? 이 double 값에는 어떻게 접근 하는가? 이 메모리는 어떻게 삭제하는 가?
double* mem = new double;
*mem = 6.2;
cout << *mem << endl;
delete mem;
11.21) 동적 메모리는 프로그램이 종료될 때 삭제되는가?
예
11.22) 메모리 누설에 대해 설명하라.
동적할당한 포인터를 삭제하지 않고 또 동적할당했을 때 원래 동적할당되었던 메모리가 접근할 수도 삭제할 수도 없게 되는 것을 말한다.
11.23) 동적 배열을 생성하고 나중에 그것을 삭제해야 한다고 가정하자. 다음 코드에서 두 가지 오류를 찾아보아라.
double x[] = new double[30];
...
delete x;
답)
double x[] = new double[];
delete [] x;
로 바꾸어야 한다.
11.24) 다음 코드에서 잘못된 부분은 무엇인가?
double d = 5.4;
double* p1 =d;
포인터에는 값이 아니라 주소를 할당해야 한다. double* p1 =&d;라고 해야 한다.
11.25) 다음 코드에서 잘못된 부분은 무엇인가?
double d = 5.4;
double* p1 =&d;
delete p1;
동적할당하지 않고 delete했다.
11.26) 다음 코드에서 잘못된 것은 무엇인가?
double* p1;
p1* = 5.4;
포인터의 초기화를 따로 하고 있다.
double* p1 =new double;
*p1 = 5.4;
로 바꿔야 한다.
11.27) 다음 코드에서 잘못된 것은 무엇인가?
double* p1 = new double;
double* p2 = p1;
*p2 = 5.4;
delete p1;
cout << *p2 << endl;
이미 삭제된 메모리를 가리키고 있다.
double* p1 = new double;
double* p2 = p1;
*p2 = 5.4;
cout << *p2 << endl;
로 바꾸어야 한다.
11.10) 동적 객체 생성과 접근
동적 객체는 다음 구문으로 heap에 동적으로생성할 수 있습니다.
인수 없는 생성자는 다음 두가지 방법으로 생성할 수 있고,
ClassName* pObject = new ClassName();
ClassName* pObject = new ClassName;
인수있는 생성자는 다음과 같이 생성할 수 있습니다.
ClassName* pObject = new ClassName(arguments);
문자열은 다음과 같이 생성합니다.
string* p = new string();
string* p = new string("abcdef");
포인터를 통해 객체 멤버에 접근하기 위해서는 포인터를 역참조해야 하며 접근할 때는 .연산자를 사용합니다.
string* p = new string("abcdef");
cout << (*p).substr(0,3) <<endl;
또, 포인터로부터 객체 멤버에 접근하기 위해서 shorthand member selection operator(화살표 연산자, arrow operator)를 사용할 수도 잇습니다.
string* p = new string("abcdef");
cout << p->substr(0,3) <<endl;
객체는 프로그램이 종료될 때 삭제되지만 delete p;로 삭제할 수도 있습니다.
checkpoint
11.28) 다음 프로그램은 올바른 프로그램인가? 만일 그렇지 않다면 수정하여라.
(a)
int main()
{
string s1;
string* p = s1;
return 0;
}
int main()
{
string s1;
string* p = &s1;
return 0;
}
로 고쳐야 한다.
(b)
int main()
{
string* p = new string;
string* p1 = new string();
return 0;
}
맞다.
(c)
int main()
{
string* p = new string("ab");
return 0;
}
맞다.
11.29) 객체를 동적으로 어떻게 생성하는가? 어떻게 삭제하는 가?
(a)코드가 잘못된 이유와 (b)코드가 올바른 이유에 빗대어 설명하시오.
a는 new연산자를 이용한 동적할당이 일어나지 않은 채 delete했기 때문에 틀렸다. 객체 포인터에 new 객체이름();나 new 객체이름; 로 동적 객체를 생성한다.
//a
int main()
{
string s1;
string* p = &s1;
delete p;
return 0;
}
//b
int main()
{
string s1;
string* p = new string();
delete p;
return 0;
}
11.30) 다음 코드에서 7번과 8번 줄(new) 모두 익명 객체를 생성하고 원의 면적을 출력한다. 8번 줄이 잘못된 이유는 무엇인가?
#include <iostream>
#include "Circle.h"
using namespace std;
int main()
{
cout << Circle(5).getArea() << endl;
cout << (new Circle(5))->getArea() << endl;
return 0;
}
동적할당은 익명객체로 만들면 안된다. 프로그램이 끝날때까지 저장되어 있고 포인터만 삭제된다.
11.11) this 포인터
this 포인터는 그 객체 자신의 멤버를 가리키는 데 사용됩니다. 매개변수와 함수 내에서 사용하려는 데이터 필드의 이름이 같을 때 요긴하게 사용합니다.
#include "Circle.h"
double PI = 3.141592;
Circle::Circle() {
radius = 1;
}
Circle::Circle(double newRadius) {
this->radius = newRadius; //a객체를 만들었다면 this->radius는 a.radius와 같다.
}
double Circle::getArea() const {
return radius * radius * PI;
}
double Circle::getRadius() const {
return radius;
}
void Circle::setRadius(double newRadius) {
this->radius = newRadius;
}
checkpoint)
11.31) 다음 코드에서 잘못된 부분을 수정하라.
Circle::Circle(double radius){
radius = radius}
수정된 코드 ▼
Circle::Circle(double radius) {
this->radius = radius;
}
11.12) 소멸자(destructor)
소멸자는 객체가 삭제될 때 자동으로 호출됩니다. 소멸자가 명시적으로 정의되지 않은 경우, 컴파일러가 기본 소멸자를 만들어줍니다. 소멸자는 생성자, 클래스이름과 동일한 이름을 갖습니다.
//Circle.h
#ifndef Circle_H
#define Circle_H
class Circle
{
public:
Circle();
~Circle();
Circle(double);
double getArea() const;
double getRadius() const;
void setRadius(double newRadius);
static int getNumberOfObjects();
private:
double radius;
static int numberOfObjects;
};
#endif
//Circle.cpp
#include "Circle.h"
double PI = 3.141592;
int Circle::numberOfObjects = 0;
Circle::Circle() {
radius = 1;
numberOfObjects++;
}
Circle::Circle(double newRadius) {
radius = newRadius;
numberOfObjects++;
}
double Circle::getArea() const {
return radius * radius * PI;
}
double Circle::getRadius() const {
return radius;
}
void Circle::setRadius(double newRadius) {
radius = newRadius;
}
int Circle::getNumberOfObjects() {
return numberOfObjects;
}
Circle::~Circle() {
numberOfObjects--;
};
//filename.cpp
#include <iostream>
#include "Circle.h"
using namespace std;
int main()
{
Circle* pCircle1 = new Circle();
Circle* pCircle2 = new Circle();
Circle* pCircle3 = new Circle();
cout << "Number of circle objects created "
<< Circle::getNumberOfObjects() << endl;
delete pCircle1;
cout << "Number of circle objects created "
<< Circle::getNumberOfObjects() << endl;
return 0;
}
checkpoint)
11.32) 모든 클래스에는 소멸자가 포함되어 있는가? 네
소멸자의 이름은 어떻게 되는가? 클래스이름과 동일
소멸자는 오버로딩이 가능한가? 소멸자는 한개만 존재하며 매개변수를 가지지 않는다.
소멸자를 재정의 할 수 있는가? 가상 함수로 소멸자가 사용되었다면 자식 클래스에서 재정의 될 수 있다.
명시적으로 소멸자를 호출할 수 있는가? 네
11.33) 다음 코드의 출력은 무엇인가?
#include <iostream>
using namespace std;
class Employee {
public:
Employee(int id) {
this->id = id;
}
~Employee() {
cout << "object with id " << id << " is destroyed" << endl;
}
private:
int id;
};
int main()
{
Employee* e1 = new Employee(1);
Employee* e2 = new Employee(2);
Employee* e3 = new Employee(3);
delete e3;
delete e2;
delete e1;
return 0;
}
//출력
object with id 3 is destroyed
object with id 2 is destroyed
object with id 1 is destroyed
11.34) 다음 코드에서 소멸자가 필요한 이유는 무엇인가? 소멸자를 추가하여라
class Person {
public:
Person() {
numberOfChildren = 0;
children = new string[20];
}
void addAChild(string name) {
children[numberOfChildren++] = name;
}
string* getChildren() {
return children;
}
int getNumberOfChildren() {
return numberOfChildren;
}
private:
string* children;
int numberOfChildren;
};
new를 이용해 child를 동적할당하기 때문에 delete로 지워주지 않으면 메모리 누수(memory leak)가 계속 발생한다.
class Person {
public:
Person() {
numberOfChildren = 0;
children = new string[20];
}
~Person() {
delete [] children;
numberOfChildren--;
}
void addAChild(string name) {
children[numberOfChildren++] = name;
}
string* getChildren() {
return children;
}
int getNumberOfChildren() {
return numberOfChildren;
}
private:
string* children;
int numberOfChildren;
};
11.13) 예제 course 클래스
#include <iostream>
using namespace std;
#include "Course.h"
class Course {
public:
Course(const string& courseName, int capacity){
this->courseName = courseName;
this->capacity = capacity;
numberOfStudents = 0;
students = new string[capacity];
}
~Course(){
delete[] students;
}
string getCourseName() const {
return courseName;
}
void addStudent(const string& name) {
students[numberOfStudents++] = name;
}
void dropStudent(const string& name) {
numberOfStudents--;
}
string* getStudent() const {
return students;
}
int getNumberOfStudents() const {
return numberOfStudents;
}
private:
string courseName;
string* students;
int numberOfStudents;
int capacity;
};
int main()
{
Course course1("Data Structures", 10);
Course course2("Database Systems", 15);
course1.addStudent("Peter Jones");
course1.addStudent("Brian Smith");
course1.addStudent("Anne Kennedy");
course2.addStudent("Peter Jones");
course2.addStudent("Steve Smith");
cout << "Number of students in course 1: " <<
course1.getNumberOfStudents() << endl;
string* students = course1.getStudent();
for (int i = 0; i < course1.getNumberOfStudents(); i++)
{
if (i == course1.getNumberOfStudents() - 1)
cout << students[i] << endl;
else
cout << students[i] << ", " << endl;
}
students = course2.getStudent();
cout << "\nNumber of students in course 2: "
<< course2.getNumberOfStudents() <<endl;
for (int i = 0; i < course2.getNumberOfStudents(); i++)
{
if(i== course2.getNumberOfStudents()-1)
cout << students[i] << endl;
else
cout << students[i] << ", " << endl;
}
course2.dropStudent("Steve Smith");
cout << "\nNumber of students in course 2: "
<< course2.getNumberOfStudents() << endl;
for (int i = 0; i < course2.getNumberOfStudents(); i++)
{
if (i == course2.getNumberOfStudents() - 1)
cout << students[i] << endl;
else
cout << students[i] << ", " << endl;
}
return 0;
}
string* students는 배열을 말합니다. 어떤 것이 들어올 지 모르므로 생성자 함수에서 동적할당 해주고, 이를 소멸자로 지워줍니다.
check point)
11.35) Course 객체가 생성될때, students 포인터의 값은 무엇인가?
배열
11.36) delete [] students 가 students 포인터에 대한 소멸자의 구현에 사용된 이유는 무엇인가?
student 포인터가 배열이기 때문이다.
11.14,11.15) 복사 생성자, 사용자 정의 복사 생성자
각 클래스에는 몇 개의 오버로딩된 생성자와 하나이 소멸자를 정의할 수 있습니다. 하지만 여기에 부가적으로 복사생성자(copy constructor)라고 합니다. 동일 클래스의 다른 객체의 데이터를 '얕은 복사'합니다.
Circle circle1(5);
Circle circle2(circle1);
를 예시로 들면, circle1의 주소를 circle2가 가리키면서 circle1의 데이터필드 값을 복사해옵니다.
#깊은 복사는 원본 객체와 완전히 독립적인 새로운 객체를 생성하여 값들을 복사하는 것을 의미하며, 얕은 복사는 원본 객체와 복사된 객체가 같은 메모리를 공유하는 방법입니다.
#include <iostream>
#include "Circle.h"
using namespace std;
int main()
{
Circle circle1(5);
Circle circle2(circle1);
cout << "After creating circle2 from circle1: " << endl;
cout << "\tcircle1.getRadius() returns "
<< circle1.getRadius() << endl;
cout << "\tcircle2.getRadius() returns "
<< circle2.getRadius() << endl;
circle1.setRadius(10.5);
circle2.setRadius(20.5);
cout << "After modifying circle1 and circle2: " << endl;
cout << "\tcircle1.getRadius() returns "
<< circle1.getRadius() << endl;
cout << "\tcircle2.getRadius() returns "
<< circle2.getRadius() << endl;
return 0;
}
course 예제)
복사 생성자를 기본으로 설정하면 얕은 복사가 일어나 같은 메모리가 할당되게 됩니다. 그렇기 때문에 항상 같은 값이 출력됩니다. 이 코드에서는 addStudent가 작동하지 않습니다.
#include <iostream>
using namespace std;
#include "Course.h"
int main()
{
Course course1("C++", 10);
Course course2(course1);
course1.addStudent("Peter Pan");
course2.addStudent("Lisa Ma");
cout << "students in course1: " <<
course1.getStudent()[0] << endl;
cout << "students in course2: " <<
course2.getStudent()[0] << endl;
return 0;
}
또, 여기서는 동적할당을 얕은 복사하기 때문에 오류가 발생합니다. 동적할당에서 new와 delete는 항상 일대일로 존재해야 하기 때문에 발생한 문제 입니다. 그렇기 때문에 동적할당 배열이라도 깊은 복사가 되도록 명시적으로 복사 생성자를 설정해야 합니다.
Course(Course& c) {
courseName = c.courseName;
students = new string[c.capacity];
numberOfStudents = c.numberOfStudents;
capacity = c.capacity;
for (int i = 0; i < numberOfStudents; i++)
students[i] = c.students[i];
}
#include <iostream>
using namespace std;
#ifndef COURSE_H
#define COURSE_H
class Course {
public:
Course(const string& courseName, int capacity){
this->courseName = courseName;
this->capacity = capacity;
numberOfStudents = 0;
students = new string[capacity];
}
~Course(){
delete [] students;
}
Course(Course& c) {
courseName = c.courseName;
students = new string[c.capacity];
numberOfStudents = c.numberOfStudents;
capacity = c.capacity;
for (int i = 0; i < numberOfStudents; i++)
students[i] = c.students[i];
}
string getCourseName() const {
return courseName;
}
void addStudent(const string& name) {
students[numberOfStudents++] = name;
}
void dropStudent(const string& name) {
numberOfStudents--;
}
string* getStudent() const {
return students;
}
int getNumberOfStudents() const {
return numberOfStudents;
}
private:
string courseName;
string* students;
int numberOfStudents;
int capacity;
};
#endif
checkpoint)
11.37) 모든 클래스에는 복사 생성자가 포함되어 있는가?
기본 복사 생성자가 항상 포함된다.
복사 생성자 이름은 어떻게 작성되는가?
복사 생성자의 이름은 클래스 이름과 같다.
복사 생성자는 오버로딩될 수 있는가?
복사 생성자는 오버로딩 안될 껄?
복사 생성자를 재정의할 수 있는가?
할수 있을껄?
복사 생성자는 어떻게 호출하는가?
Course course2(course1);
11.38) 다음 코드의 출력은 무엇인가?
#include <iostream>
#include <string>
using namespace std;
int main() {
string s1("ABC");
string s2("DEFG");
s1 = string(s2);
cout << s1 << endl;
cout << s2 << endl;
return 0;
}
DEFG
DEFG
11.39) s1 = string(s2);는 다음 코드와 동일한가?
s1=s2;
어느 것이 더 좋은가?
동일하지 않다. s1 = string(s2);은 얕은 복사가 되고 s1=s2;은 깊은 복사가 된다. 상황에 따라 다르지만 메모리 면에서는 s1 = string(s2);
'c, c++ > c++로 시작하는 객체지향 프로그래밍' 카테고리의 다른 글
15.1~15.4, 15.8) 상속 (0) | 2024.05.02 |
---|---|
12.1~12.5 (2) | 2024.04.25 |
11.1~11.5 (1) | 2024.04.04 |
10.3~10.10 (2) | 2024.03.28 |
9.8~9.10)클래스에서 함수와 변수 (0) | 2024.02.02 |