#pragma once 왜 있느냐?
- 소스 코드를 컴파일 할 때 해당 header file을 한번만 compiler에 포함할 것을 명시.
this 포인터에 대해 설명하라
- this 포인터란, 클래스나 구조체, union타입의 멤버 함수(static하지 않음) 안에서 접근할 수 있는 포인터이다. 멤버 함수가 호출되는 객체를 가르킨다.
(의문점, this포인터를 사용하면 멤버 함수의 정의에서 매개변수에 그 멤버 함수를 사용하고 접근하고 있는 객체의 이름을 표시할 수는 없을까? 단순히 멤버 변수의 값만 출력할 수 있는 것인가?)
생성자에서 default인자에 대해 설명하라
- default인자란, 생성자 호출 시 인수 값이 제공되지 않을 경우, 컴파일러에서 자동으로 값을 할당하도록 함수 선언에 제공된 값이다. (의문점, 꼭 '선언'시 default값이 정해져야하는것인가? 아니다. 함수 정의 시 넣어도 된다. 그러나 deafult constructor을 사용하기 위해서는, 다른 생성자를 정의해서는 안되며 값을 내 맘대로 초기화 시켜주고 싶으면 직접 생성자를 정의하여 값을 대입해줘야 한다. )
/* default constructor에 대한 추가 의문점
- 프로그래머가 Person() 이든 Person(int m, int n)이든 생성자를 하나라도 정의했을 때 기본 생성자가 만들어지지 않는다. 코드 내에 생성자가 하나도 없고, main에서 Person a;와 같이 객체가 생성되면 해당 객체의 멤버 변수 안에 null값이나 쓰레기 값이 할당되게 하는 것이 기본 생성자의 역할이다. // 맞나?
그런데 여러 코드에서는 매개변수를 가지고 있지 않거나 default값이 설정되어 있는 매개변수가 있는 생성자를 기본 생성자라고 칭하곤 한다.
- 모순이라고 생각하는 것은, 프로그래머가 Person을 따로 지정하지 않았을 때 함수에서 내부적으로 호출되는 것을 기본 생성자라고 하는데, 생성되어있는 Person을 기본 생성자라 칭하면 이미 프로그래머가 Persond을 따로 지정하였다는 점에서 기본 생성자를 부를 수 없는 것이 아닌가?
*/
--> 해결 : default 생성자는 소스 코드 내의 생성자의 유무와 상관없이 항상 프로그램에서 제공되는 것이다.
#include <iostream>
using namespace std;
class Sum{
private:
int x;
int y;
public:
Sum(int temp_x = 1, int temp_y= 2)
{
x = temp_x;
y = temp_y;
}
void print() {
cout << "x = " << x << " y = " << y << endl;
}
};
int main()
{
Sum sum;
sum.print(); // x = 1, y = 2
return 0;
}
default 인자를 사용하는 바른 예.
이때 Sum sum; 아니라 Sum sum()이라고 사용하지 않도록 주의하라. sum()과 같이 사용하면 동일한 소스코드에 있는 함수 sum()과 혼동된다.
하나의 숫자만을 넣으면 왼쪽부터 차례로 값이 할당되는 것을 볼 수 있다.
즉 x = 9, y = 2가 된다.
분리시켜서 함수 선언에 default 인자값을 넣어보자면 이러하다...
#pragma once
#include <iostream>
using namespace std;
#ifndef SUM_H
#define SUM_H
class Sum {
private:
int x;
int y;
public:
Sum(int = 1, int = 2);
void print();
};
#endif SUM_H
#include <iostream>
using namespace std;
#include "sum.h"
Sum::Sum(int tempx , int tempy )
{
x = tempx;
y = tempy;
}
void Sum::print() {
cout << "x = " << x << " y = " << y << endl;
}
int main()
{
Sum sum(9);
sum.print(); // null 값 출력
return 0;
}
즉, 꼭 함수 선언이 아니더라도 생성자 정의에서 default 인자값을 할당시킬 수 있다는 것.
Composition(복합/합성)에 대해 설명하라
A common form of software reusability is composition, in which a class has objects of other classes as members.
클래스는 다른 클래스의 객체를 구성원으로 포함한다. private 상속과 동일한 의미(해당 클래스의 public 멤버들만 사용 가능)
클래스의 멤버 변수에 다른 클래스 자료형의 객체가 들어오는 것을 Composition이라고 한다.
→ Has-a 관계라고 표현하기도 한다.
→ 복합 관계에서의 멤버 객체를 초기화하기 위해서는, 멤버 초기화기에서 객체 생성자의 인자를 통해 생성자에게 인수를 전달
? 이 클래스 내애서 멤버 함수는 이 멤버 변수(객체)에 대한 얼마만큼의 접근 권한을 가질까?
→ private까지도 가능할 걸...? (x)
→ public까지만 가능하고, private는 Date클래스의 지역변수, Employee는 외부 클래스이므로 접근할 수 없다!
밑에 접은 글 보삼 Composition의 예시(강노)
#pragma once
#ifndef DATE_H
#define DATE_H
class Date {
public:
Date(int = 1, int = 1, int = 1900);
void print() const;
~Date();
private:
int month;
int day;
int year;
int checkDay(int) const;
};
#endif
#include <iostream>
using namespace std;
#include "Date.h"
Date::Date(int m, int d, int y)
{
month = m;
day = d;
year = y;
}
int Date::checkDay(int a) const {
// 뭐시기
}
void Date::print() const {
cout << month << "/ " << day << "/ " << year << endl;
}
Date::~Date() {
cout << "소멸자가 호출되었습니다. " << endl;
}
이렇게 Date에 대한 클래스를 만들어주고
#pragma once
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
#include <iostream>
using namespace std;
#include <string>
#include "Date.h"
class Employee {
private:
string name;
int age;
Date date; // 입사일
public:
void printInfo() const;
};
#endif
Date 자료형 멤버 변수를 가지는 class Employee를 지정해주었다.
그러면 이 Employee 클래스에서 Date변수로의 접근은 어떻게 얼마나 가능할까?
#include <iostream>
using namespace std;
#include "Employee.h"
#include <string>
Employee::Employee(string n, int a, Date d) {
name = n;
age = a;
date = d;
}
void Employee::printInfo()const {
cout << name << " " << age << " " << "입사일 : ";
date.print();
cout << endl;
}
int main() {
Date a (1, 2, 2001);
Employee ab("민겸", 21, a);
ab.printInfo();
return 0;
}
printInfo()함수에 집중해보자. public으로 정의된 print함수에 의해 간접적으로 멤버 변수인 month, day, year을 출력하였다. 하지만 다음과 같이 private함수에 직접적으로 접근하려고 하면 에러가 뜬다.
check O for True of X for False
- C is an object-oriented language. (X)
- C++ is an object-oriented language. (O)
- Binary scope resolution operator is used to define functions outside of classes. (O) - What is the Binary Scope resouliton operator? 이항 스코프 식별 연산자 ( :: )
- The dot(.) operator is used for direct member selection via object name. (O) - 점 연산자는 객체 이름을 통해 멤버를 직접 선택하는 것에 사용된다.
- Private member variables cannot be accessed from outside the class. (X) - 다른 이유로 접근할 수 있다. (friend function ... !)
- Objects can be used as arrays. (O) - 객체는 배열들로 사용될 수 있다.
- In pointer objects, you need to access members using the arrow(->) operator. (O) - 포인터 객체에서, 멤버에 화살표 연산자를 이용해 접근해야한다.
- The constructor of the class and the default constructor have the same meaning. (X) - 클래스의 생성자와 기본 생성자는 같은 의미이다. (NO -차이점 : 매개변수의 유무, 기본 생성자는 내부적으로 호출된다. (항상))
- Destructors are always called in reverse order of the constructor. (X) - 소멸자는 생성자의 역순으로
항상출력된다. - Const objects can only call const functions. (o) - const 객체는 const 함수만 호출할 수 있다.
Fix Errors!
1)
class Noon {
private:
const int hour;
const int minute;
const int second;
public:
Noon() {
hour = 12;
minute = 0;
second = 0;
}
void greet() {
cout << "Hello" << endl;
}
};
key point : const 멤버 변수는 생성자에서 Member Initializer를 이용해 초기화해야한다.
class Noon {
private:
const int hour;
const int minute;
const int second;
public:
Noon()
: hour(12), minute(0), second(0)
{
// Empty
}
void greet() {
cout << "Hello" << endl;
}
};
2)
class Time {
private:
int hour;
int minute;
int second;
public:
Time(int = 0, int = 0, int);
void print();
};
int main(){
Time time;
Time * time_ptr = &time;
time_ptr.print();
}
class Time {
private:
int hour;
int minute;
int second;
public:
Time(int = 0, int = 0, int = 0);
void print();
};
int main()
{
Time time;
Time* time_ptr = &time;
time_ptr->print();
}
key point
- 클래스의 생성자에서 매개변수에 디폴트 인자를 넣어줄 때는, 오른쪽부터 인자를 넣어준다.
- time_ptr은 포인터 변수이다. 따라서 화살표 연산자를 이용해 Time 클래스의 public 멤버 함수, print함수를 호출한다.
class Time {
public:
int hour;
int minute;
int second;
}
int main() {
Time time;
Time* time_ptr = &time;
*time_ptr.hour = 12;
}
class Time {
public:
int hour;
int minute;
int second;
};
int main() {
Time time;
Time* time_ptr = &time;
(*time_ptr).hour = 12;
} // 역참조 하여 멤버 변수에 값 대입하기
마지막 코드의 의도는 포인터 변수를 역참조하여 값을 대입하는 것이다.
이때 역참조하였음을 괄호로 명시해 hour 멤버 변수가 (*time_ptr), 객체의 값을 가리키도록 한다.
그리고, Time 클래스의 중괄호의 끝에 세미콜론이 빠져있다.
Write the output of the code below.
#include <iostream>
class Date {
public:
Date() {
std::cout << "Date created" << std::endl;
}
~Date() {
std::cout << "Date destroyed" << std::endl;
}
};
class Employee {
private:
Date hireDate;
public:
Employee() {
std::cout << "Employee created" << std::endl;
}
~Employee() {
std::cout << "Employee destroyed" << std::endl;
}
};
void func() {
static Date date1;
Date date2;
Employee employee2;
}
int main() {
Employee employee1;
func();
return 0;
}
정답
Date created // employee1.hireDate의 생성자 호출
Employee created // employee1 객체의 생성자 호출
Date created // func()함수 안에서 static Date date1의 생성자 호출
Date created // func() 함수 안에서 Date date2의 생성자 호출
Date created // func() 함수 안에서 employee2.hireDate의 생성자 호출
Employee created // func()함수 안에서 employee2 생성자 호출
Employee destroyed // func()이 끝나고 employee2 소멸자 호출
Date destroyed // employee2.hireDate의 소멸자 호출
Date destroyed // date2의 소멸자 호출
Employee destroyed // employee1의 소멸자 호출
Date destroyed // employee1.hireDate의 소멸자 호출
Date destroyed //date1의 소멸자 호출
key point : static, global, local 변수들마다 소멸되는 순서를 계산한다.
실습 문제
// time.h
#ifndef TIME_H
#define TIME_H
class Time {
private:
int hour;
int minute;
int second;
public:
Time(_____); // must provide default arguments
int get_hour() const;
int get_minute() const;
int get_second() const;
void print_standard() const;
void print_universal() const;
void set_hour(int);
void set_minute(int);
void set_second(int);
void set_time(int, int, int);
void tick();
};
#endif
//time.cpp
_____ // include headers and set namespaces
Time::Time(int h, int m, int s) {
set_time(h, m, s);
}
int Time::get_hour() const {
return hour;
}
int Time::get_minute() const {
return minute;
}
int Time::get_second() const {
return second;
}
void Time::print_standard() const {
cout << ((hour == 0 || hour == 12) ? 12 : hour % 12) << ":"
<< setfill('0') << setw(2) << minute << ":"
<< setfill('0') << setw(2) << second << (hour < 12 ? " AM" : " PM");
}
void Time::print_universal() const {
cout << setfill('0') << setw(2) << hour << ":"
<< setfill('0') << setw(2) << minute << ":"
<< setfill('0') << setw(2) << second;
}
void Time::set_hour(int h) {
_____ // check hour range(0~23)
}
void Time::set_minute(int m) {
_____ // check minute range(0~59)
}
void Time::set_second(int s) {
_____ // check second range(0~59)
}
void Time::set_time(int h, int m, int s) {
set_hour(h);
set_minute(m);
set_second(s);
}
void Time::tick() {
_____
}
// main.cpp
#include <iostream>
#include "time.h"
using std::cout;
using std::endl;
int main() {
_____
return 0;
}
빈칸을 채워보자!
Time(int =0, int = 0, int = 0);
#include <iostream>
using std::cout;
using std::endl;
#include <iomanip>
using std::setw;
using std::setfill;
#include "time.h"
void Time::set_hour(int h){
hour = (h >= 0 && h < 24) ? h : 0
}
void Time::set_minute(int m){
minute = (m >= 0 && m < 60) ? m : 0
}
void Time::set_second(int s){
second = (s >= 0 && s < 60) ? s : 0
}
void Time::tick() {
set_second(get_second() + 1);
if (get_second() == 0) // 유효성 검증으로 second = 0이 되었을 때
{
set_minute(get_minute() + 1);
if (get_minute() == 0)
{
set_hour(get_hour() + 1);
}
}
}
tick()은 조교님이 알려주신 코드 .. 내 코드는 쓰레기였다.
멤버변수나 대입 연산자를 안 쓰고 굳이 get, set을 통해 멤버 변수를 관리하는 것은 유효성 검사를 하기 위함이다.
중간고사 족보 풀이 끝
'Major Study > Object Oriented Programming' 카테고리의 다른 글
연산자 오버로딩 / 상속 / 다형성 구현 프로젝트 해결 과정 (0) | 2021.10.08 |
---|---|
객체지향 프로그래밍2 상속, 연산자 오버로딩, 다형성, 템플릿 관련 의문점 정리 및 해결 (2) | 2021.06.15 |
C++ template 내용 정리(열혈 C++, 강의노트, 기타 자료 참고) (0) | 2021.06.15 |
객체지향 프로그래밍2 기말고사 대비 문제 wirte-up (0) | 2021.06.14 |
객체지향 프로그래밍 프로젝트 (상속과 다형성, 가상함수) 해결 과정 / 가상 함수, 다형성 개념 정리 (0) | 2021.05.31 |