1. Overloading
같은 클래스에서 만든 인스턴스끼리 덧셈이 가능할까?
정답은 아니오다. 우리는 인스턴스끼리의 덧셈을 정의한 적이 없다.
인스턴스끼리 덧셈을 하려면 우리는 Overloading이라는 것을 해야한다.
Overloading이란, "같은 이름 다른 정의" 이다. C++은 하나의 function에 대해 여러 정의를 할 수 있게 해준다.
#include <iostream>
using namespace std;
class Point {
private:
int x;
int y;
static int numCreatedObjects; //static : 모든 객체가 공동으로 사용
public:
Point() : x(0), y(0) {
numCreatedObjects++;
} //constructor 1
Point(int _x, int _y) : x(_x), y(_y) {} //constructor 2
~Point() {
cout << "Destructed..." << endl;
} //destructor
void setXY(int _x, int _y) {
this->x = _x;
this->y = _y;
} //setter func
int getX() const { return x; } //getter func
int getY() const { return y; } //getter func
Point operator+(Point& pt2) {
Point result(this->x + pt2.getX(), this->y + pt2.getY()); //여기서 this는 pt1임
return result;//result라는 point 생성 후 출력
} //설명
Point& operator=(Point& pt) { //&를 사용하는 이유 : this가 포인터이므로 dereference 하기 위해서 . pt는 result임
this->x = pt.getX();
this->y = pt.getY();
return *this;
}
};
//설명:
main 함수에
*pt2 = *pt1 + *pt2 와 같은 코드가 있다고 하면, pt1(pt2)와 같은 형태로 실행된다.
2. 복사로 하면 인스턴스 생성 한번 더 됨. 참조로 해야 인스턴스 생성 안됨
public:
void hack_all_info(Point &pt) { //참조!
cout << "Hacked by Spypoint" << endl;
cout << "x: " << pt.getX() << endl;
cout << "y: " << pt.getY() << endl;
cout << "numCreatedObj.: " << pt.getNumCreatedObject() << endl;
}
};
3. const method
C++에서 class안에서 user define function을 만들 때는 const method를 붙여줘야 한다.
int getX() const{
return x;
}
int getY() const {
return y;
}
4. pointer에도 &를 붙여줄 수 있다. 이러면 참조로 pointer 주소를 가져오게 된다.
Point operator-( const Point &pP) {
Point result(this->x - pP.getX(), this->y - pP.getY());
return result;
}
5. operator overloading을 이용하면 그 클래스에 직접 다가갈 수 있게 되므로, private 변수거나 setter function이 없어도 변수를 수정할 수 있다.
Account operator+(const Account & account) {
balance += account.getBalance();
return Account(this->getName(), this->getId(), this->getBalance());
}
Account operator-(const Account & account) {
balance -= this->getBalance();
return Account(this->getName(), this->getId(), this->getBalance());
}
6. cout << 할땐 friend 쓸것
friend 키워드를 사용하여 operator<<를 정의하는 이유: operator<<가 클래스의 private 및 protected 멤버에 접근할 수 있도록 하기 위해서이다.
일반적으로 operator<<는 클래스의 비멤버 함수로 정의되며, 클래스 외부에서 정의되기 때문에 클래스의 private 멤버에 접근할 수 없다. 그러나 friend 키워드를 사용하면 가능해진다.
friend ostream& operator<<(ostream& cout, const Account& account) {
cout << "학번: " << account.getId() << ", 이름: " << account.getName() << ", 잔액: " << account.getBalance() << endl;
return cout;
}
7. operator =
Point& operator=(const Point& pP) {
this->x = pP.getX();
this->y = pP.getY();
return *this;
}
2024.05.23
8. costructor 상속은 다음과 같다
Character() : Avengers::Avengers(){}
2023.05.27
9. template <typename T> = template <class T>
10. template을 사용할 땐 사용할 때마다 위에 써줘야 한다.
template<class T>
Point<T>::Point(T _x, T _y) : x(_x), y(_y) {};
11. ary는 1의 주소를 나타내며, begin(), end()함수도 주소를 리턴하는 함수이다.
#include <iostream>
#include <vector>
using namespace std;
int main() {
int ary[] = { 1,2,3,4 };
int* pBegin, * pEnd;
pBegin = ary; //pBegin : 주소 , ary = 1의 주소
pEnd = ary + 4;
for (int *pIter = pBegin; pIter < pEnd; pIter++) //pIter :포인터(주소값 저장)
cout << *pIter << "\t";
cout << endl;
vector <int> v{ 10, 20, 30, 40 };
auto iter_begin = begin(v);
auto iter_end = end(v);
for (auto iter = iter_begin; iter < iter_end; iter++)
cout << *iter << "\t";
}
12. 반복자 연산은 부등호를 쓸 수 없다. 배열이라는 보장을 할 수 없기 때문이다. 그래서 !=를 사용해야 한다.
template <typename Iter>
void print(const Iter& iter_begin, const Iter& iter_end) {
for (Iter iter = iter_begin; iter != iter_end; iter++)
cout << *iter << "\t";
cout << endl;
}
13. 문제가 reverse로 주어졌을 땐, while을 사용하는 것이 통상적이다.
template</* 구현 */>
void print_reverse(const Iter& iter_begin, const Iter& iter_end) {
Iter iter = iter_end;
/* 구현 */
cout << endl;
}
그리고 Iter iter = iter_end;로 주어졌으므로 while문을 사용하여 조건을 하나만 더 추가하는 것이 맞다.
14. lambda 함수와 int(*f)(int,int)의 사용
int sum(int x, int y) { return x + y; }
int mult(int x, int y) { return x * y; }
int evaluate(int(*f)(int, int), int x, int y) {
return f(x, y);
}
int evaluate(int(*f)(int, int), int x, int y) {
return f(x, y);
}
cout << evaluate(&sum, 2, 3) << endl;
cout << evaluate(&mult, 2, 3) << endl;
cout << evaluate([](int x, int y)->int {return x + y; },20,30) << endl;
cout << evaluate([](int x, int y)->int {return x * y; },20,30) << endl;
둘은 같은 표현이다!
15. 람다함수 evaluate와의 호환
#include <iostream>
#include <functional>
using namespace std;
int evaluate2(function<int(int, int)> f, int x, int y) {
return f(x, y);
}
int main() {
int a = 10, b = 20;
cout << evaluate2([a](int x, int y) {return a + x + y; }, 2, 3) << endl;
a = 20;
cout << [&](int x) {return a * x; }(10) << endl;
cout << "a: " << a << endl;
return 0;
}
2024.05.29
16. transform은 람다함수랑 같이 쓰려 return 값이 있어야 반영된다.
transform(begin(v1), end(v1), begin(v2), [](int& elem) { elem *= elem; return elem; });
17. switch 문 항상 마지막엔 break를 붙여줘야 한다.
18. template을 사용한 함수를 밖에서 쓰게되면 항상위에다가 템플릿 정의를 해줘야한다. 비록 템플릿을 당장 안쓸지라도
template<typename T>
class CList {
public:
CList();
~CList();
bool IsEmpty();
bool IsFull();
void Add(T data);
void Delete(T data);
void Print();
private:
T m_Array[5];
int m_Length;
};
template<typename T>
bool CList<T>::IsEmpty() {
return true;
}
19. sort 함수 사용법
#include <algorithm>
vector
sort(vec.begin(), vec.end());
array
a[10];
sort(a, a+10);
내림차순 정렬(큰게 앞으로)
sort(vec.begin(), vec.end(), greater<int>());
20. switch 문에서 break 안쓰면 : 다음 case로 넘어감;
21. iterator : 배열 요소를 가르키는 포인터
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// Iterator를 사용하여 벡터의 모든 원소 출력
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
return 0;
}
22. lambda 함수는 함수 변수와 [] 안 변수 이름이 같으면 충돌이 일어난다
2024.06.04
23. 여기서 v.at(index)함수의 사용과 v[index]의 사용에서는 차이가 있다.
v[index]는 그냥 프로그램 충돌이 나버리고, v.at(index)는 catch 구문이 실행된다.
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector <int> v{ 1,2,3,4 };
int index;
cin >> index;
try{ cout << v.at(index) << endl; }
catch (exception& e) {
cout << e.what() << endl;
cout << "인덱스 에러" << endl;
}
cout << "[Program is running]" << endl;
return 0;
}
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector <int> v{ 1,2,3,4 };
int index;
cin >> index;
try{ cout << v[index] << endl; }
catch (exception& e) {
cout << e.what() << endl;
cout << "인덱스 에러" << endl;
}
cout << "[Program is running]" << endl;
return 0;
}
2024.06.07
24. classA의 변수를 classB가 쓴다면 classA를 먼저 선언해야한다.
class Vacation {
public:
int virtual bookHotels() {}
int virtual bookFlights() {}
int virtual bookTours() {}
};
class Director
{
public:
static Vacation *vacation;
static void book(int type); // 클라이언트는 이 함수만 호출 가능
};
25. 오버라이드, 상속 또한 헤더파일에서 처리하며, 이는 ""로 불러와야 한다
#include "vacation.h"
26. 동적 할당된 배열에 대해선 garbage value에 대한 적절한 처리가 필요하다.
class Student {
string name;
Schedule schedule;
public:
Student(string _name) : name(_name){}
string getname() {
return name;
}
Schedule getSchedule() {
return schedule;
}
void print() {
cout << "Student name: " << name << endl;
cout << "List of Courses" << endl;
for (int i = 0; i < 10; i++) {
if ((schedule.getnames())[i] != "") { //적절한 처리
cout << (schedule.getnames())[i] << endl;
}
}
}
};
class Schedule {
string* names = new string[10];
public:
Schedule() {
for (int i = 0; i < 10; i++) {
names[i] = "";
}
}
void addCourse(Course _course) {
for (int i = 0; i < 10; i++) {
if (names[i] != "") {
names[i] = _course.getname();
}
}
}
string* getnames() {
return names;
}
};
27. 다음과 같이 : 로 constructor 선언 안 할땐 : 떼야함
잘못된 코드)
Schedule::Schedule() : {
string* names = new string[10];
for (int i = 0; i < 10; i++) {
names[i] = "";
}
}
올바른 코드
Schedule::Schedule(){
string* names = new string[10];
for (int i = 0; i < 10; i++) {
names[i] = "";
}
}
28. 리턴값이 배열이면 함수도 다음과 같이 써야한다
string* Roster::getnames() {
return names;
}
29. 순환 참조 해결법 : cpp 파일에도 #include "header.h"를 해준다. 헤더파일에는 class를 선언만 해주거나, #include "header.h" 를 해준다.
ex) course.cpp
#include "course.h"
#include "roster.h"
ex) course.hpp
#pragma once
#ifndef course_hpp
#define course_hpp
#include <iostream>
#include <string>
#include "roster.h"
using namespace std;
class Course {
string name;
int unit;
Roster roster;
public:
Course(string, int);
string getname();
Roster& getRoster();
void print();
};
#endif // !course_hpp
30. 파일 분할 할때 public 안쓰면 다 private로 인식해서 골때려짐.. 꼭 public인거 챙겨서 쓸것!!
31. 앞에서 배열 선언했는데 또 type으로 선언하면 초기화됨..
선언했으면 다음과 같이 쓸 것
Schedule::Schedule(){
names = new string[10];
for (int i = 0; i < 10; i++) {
names[i] = "";
}
}
string* names = new string[10]; 이렇게 하면 안됨
32. pass by reference 유형 2가지
앞에 &다는 유형
Roster& Course::getRoster() {
return roster;
}
변수에 & 다는 유형
void Roster::addStudent(Student &_student) {
for (int i = 0; i < 300; i++) {
if (names[i] == "") {
names[i] = _student.getname();
break;
}
}
}
33. const를 쓰는 이유
단순히 메모리 효율 측면에서 말고,const는 pass by value일때 destructor가 실행되는 것을 막을 수 있다.
34. const를 쓰는 경우
그러나 pass by reference일땐 const사용을 생각해봐야한다.
void가 아닌 리턴값이 있는 함수일 때는 객체도 const로 받아야 오류가 나지 않는다.
따라서 void로 쓰인 함수이면서, 뭔갈 변화시키지 않는 함수랑 const랑 사용하는 것을 추천한다.
'C++' 카테고리의 다른 글
[Data Structure] Reviewing Up wrong C++ codes 2 (0) | 2024.11.30 |
---|---|
[Data Structure] 중간고사 정리 (2) | 2024.10.20 |
[Data Structure] Reviewing Up wrong C++ codes (1) | 2024.10.04 |
[C++] Vector와 Array (0) | 2024.04.21 |
[C++]중간고사 공부 로그 (0) | 2024.03.15 |