
int* a[3] // int*를 값으로 갖는 원소3개짜리 배열 a
int (*b)[3] // int[3]인 배열을 가리키는 포인터 b
int arr[3]{ 1, 2, 3 };
int (*ptr)[3] = arr; // 에러 발생
int (*ptr)는 3개의 int로 이루어진 배열을 가리키는 포인터
arr은 int 3개짜리 배열
arr은 배열의 첫 번째 요소를 가리키는 포인터(int*)&arr은 int 3개짜리 배열 전체의 주소를 가리키는 포인터(int(*)[3])&arr로 배열의 주소값을 받았을 경우 당연히 *(&arr) 해야 배열로 사용 가능
int arr[3] {1, 2, 3};
int *p1 = arr; // 올바른 방식
int (*p2)[3] = &arr; // 올바른 방식
p1은 배열처럼 사용 가능 ex) p1[1], *(p1 + 1)
p2는 아래와 같이 사용 가능
int arr[3] {1, 2, 3};
int (*p2)[3] = &arr;
// p2는 arr를 통으로 가리키는 주소이므로 역참조 해야 배열로 사용 가능
std::cout << (*p2)[0]; // 1
std::cout << (*p2)[1]; // 2
std::cout << (*p2)[2]; // 3
int data[2][3] = { {1,2,3}, {4,5,6} };
int (*p3)[3] = data; // 그냥 data는 첫 번째 원소({1,2,3} 배열)의 주소값
std::cout << (*p3)[0]; // 1
std::cout << (*(p3+1))[0]; // p가 {1,2,3} 배열이니 p+1은 그 다음 배열인 {4,5,6}
// == p[1][0] == 4
int (*p4)[2][3] = &data; // p4도 배열 통짜로 받아야하므로 &data로 주소값 받음
std::cout << (*p4)[1][2]; // 역시 역참조 해야 배열로 사용 가능
class Person {
public:
string name;
int age;
// 기본 매개변수가 있는 생성자
Person(string n = "DefaultName", int a = 18)
{
name = n;
age = a;
}
};
int main() {
Person p1; // 기본값 사용 (DefaultName, 18)
Person p2("Bob", 30); // 값을
}
class Person {
public:
string name;
int age;
Person(string n, int a)
{
name = n;
age = a;
}
};
int main() {
Person p("a", 30); // ok
Person p2; // error. Defualt 생성자 사용되지 않음
}
class A
{
int a;
public:
A(int input = 10); // 선언부에만 표현
};
A::A(int input) : a(input) {} // 정의부에는 X
class Animal
{
int a;
int b;
public:
Animal(int input1 = 10, int input2 = 5) : a(input1), b(input2) {}
};
Animal animal()로 생성 시 → a = 10, b = 5 저장Animal animal(4)로 생성 시 → a = 4, b = 5 저장Animal animal(4, 7)로 생성 시 → a = 4, b = 7 저장Animal animal( , 7)은 잘못된 문법. 왼쪽 기본인자부터 교체된다
ifdef, ifndefdefine, ifdef, ifndef는 모두 전처리기 지시문으로, 특정 매크로가 정의되어 있는지를 검사하여 그에 따라 코드의 일부를 컴파일할지 말지를 결정
이들의 위치는 어디에 있어도 상관 없으나, define정의가 등장하기 전까지는 그 이름이 인식되지 않음
define 매크로명: 매크로명을 정의
ifdef 매크로명 ~ endif: 매크로명이 정의되어 있으면 ~ 부분을 컴파일
ifndef 매크로명 ~ endif: 매크로명이 정의되어 있지 않을 때 ~부분 컴파일
int main() {
// 매크로가 정의되기 전에 사용하면 컴파일 안 됨
#ifdef DEBUG
printf("Hello\n"); // 컴파일 안 됨
#endif
#define DEBUG // 이제 정의
#ifdef DEBUG // 정의 되었으니 컴파일 가능
printf("Now Defined\n"); // 실행됨
#endif
}
ifndef를 이용// Student.hpp
#ifndef STUDENT_H_ // 헤더파일이 처음 포함될 경우 컴파일
#define STUDENT_H_ // 컴파일 시작했으므로 다시 바로 정의
class Student
{
...
};
#endif
#pragma once를 더 자주 사용하고 이게 더 좋긴 함a는 b이다의 관계로 부모(b)-자식(a) 관계를 파악사자는 동물이다가 성립하므로 동물이 부모클래스, 사자가 자식 클래스
class 내의 멤버변수를 virtual를 이용해 가상함수로 만들면 이 클래스를 상속한 자식 클래스에서 이 가상함수를 각자 입맛에 맞게 구현
virtual로 정의하면 가상 함수 테이블이 생성되어서 각 자식 클래스가 만든 함수가 이 가상 함수 테이블에 등록된다
이러한 관계는 런타임에 결정되기 때문에 다른 멤버함수와는 다르게 가상 함수 테이블을 이용하여 동적으로 연결한다
virtual <T> foo() = 0;처럼 가상함수를 정의하지 않으면 순수 가상 함수