• 함수는 작업을 수행한 후 제어권을 호출자에게 반환하는 코드 블록입니다.
• C 및 C++ 프로그래밍에서는 모든 실행 가능한 코드가 함수 내에 존재합니다.
• 함수는 종종 프로그램을 한 번 실행하는 동안 여러 곳에서 여러 번 실행(호출)됩니다.
• 서브루틴을 종료하면 프로그램은 콜 후 포인트로 분기(복귀)합니다.
• 함수의 연산은 매개 변수를 사용하여 변경할 수 있습니다.
• 함수 선언의 인수는 함수 호출로 전달된 매개변수에 명확하게 대응합니다.
• 함수에 리턴 타입이 있는 경우 콜은 반환값을 가진 것으로 평가되어 변수로 저장 가능.
#include <iostream>
using namespace std;
float calculateCircle(int radius) {
return 3.14 * radius * radius;
}
int main() {
int min, max, radius;
cout << "Enter Min (1~10) : " ;
cin >> min;
cout << "Enter Max (Min~10) : " ;
cin >> max;
for (int i = min; i < max + 1; i++) {
cout << "Radius " << i << "=3.14x" << i << "x" << i << "=" << calculateCircle(i) << "\n";
}
}
결과:
Enter Min (1~10) : 2
Enter Max (Min~10) : 10
Radius 2=3.14x2x2=12.56
Radius 3=3.14x3x3=28.26
Radius 4=3.14x4x4=50.24
Radius 5=3.14x5x5=78.5
Radius 6=3.14x6x6=113.04
Radius 7=3.14x7x7=153.86
Radius 8=3.14x8x8=200.96
Radius 9=3.14x9x9=254.34
Radius 10=3.14x10x10=314
• 인라인 함수가 'inline' 키워드를 사용하여 정의되면 함수가 호출될 때마다 컴파일러는 함수 호출을 함수의 실제 코드로 바꿉니다.
• 인라인 함수는 function-calling-overhead가 저장되기 때문에 일반 함수보다 조금 빠르게 실행되지만 메모리 패널티가 발생합니다.
– 인라인 함수를 10회 호출하면 함수의 복사본이 코드에 10개 삽입됩니다.
• 인라인 함수는 자주 호출되는 작은 함수에 적합합니다.
변수로 따로 선언하지 않고 바로 함수의 반환값을 사용할 수 있는 함수로 보인다.
#include <iostream>
using namespace std;
inline int inc(int x) {
return x + 1;
}
int main() {
cout << inc(1) << endl;
}
재귀 함수는 자신을 호출하거나 함수 호출의 잠재적 사이클에 있는 함수입니다.
#include <iostream>
using namespace std;
int Factorial(int n) {
if (n == 1)
return 1;
return Factorial(n - 1) * n;
}
int main() {
int result = Factorial(4);
cout << "Factorial :" << result << "\n";
return 0;
}
#include <iostream>
using namespace std;
int Fibo(int n) {
if (n == 1)
return 1;
if (n == 2)
return 1;
return Fibo(n - 1) + Fibo(n-2);
}
int main() {
int result = Fibo(8);
cout << "Fibo :" << result << "\n";
return 0;
}
• 클래스는 데이터 및 함수(메서드라고도 함)를 멤버로 하는 키워드 클래스를 사용하여 선언된 사용자 정의 유형 또는 데이터 구조입니다.
• 클래스는 데이터 구조의 확장된 개념입니다. 데이터 구조처럼 데이터 구성원을 포함할 수 있지만 구성원으로서의 기능도 포함할 수 있습니다.
• 인스턴스는 클래스의 구체적인 선언입니다.
• 정식 "instance"는 "object"와 동의어입니다.
• 인스턴스마다 독자적인 데이터가 있습니다.
• 생성된 인스턴스의 생성을 인스턴스화라고 합니다.
지정자 | 접근성 |
---|---|
private | Accessible only within the same class (not from outside the class) 따로 private:으로 쓰지 않아줘도 기본적으로 클래스 내의 변수들은 private으로 저장되는 듯 함 |
public | Accessible within the class as well as from outside the class. |
protected | The members declared as "protected" cannot be accessed from outside the class, but can be accessed from a derived class. This is used when inheritance is applied to the members of a class. 클래스 외부에서 액세스할 수 없지만 파생 클래스에서 액세스할 수 있습니다. 이는 상속이 클래스 멤버에 적용될 때 사용됩니다. |
클래스의 경우 선언을 클래스 내에서, 그 메서드의 정의를 클래스 밖에서 할 수 있다
ex) Calculate Area 메서드를 클래스 밖에서 정의했다.
#include <iostream>
using namespace std;
class Quadrangle {
private:
int width;
int height;
int area;
public:
int CalculateArea(int argWidth, int argHeight);
void SetWidth(int width){
Quadrangle::width = width;
}
void SetHeight(int height) {
Quadrangle::height = height;
}
};
int Quadrangle::CalculateArea(int argWidth, int argHeight) {
width = argWidth;
height = argHeight;
area = width * height;
return area;
}
void main() {
int w, h;
Quadrangle cQ;
cout << "Enter Width : ";
cin >> w;
cout << "Enter Height : ";
cin >> h;
cQ.SetHeight(h);
cQ.SetWidth(w);
cout << "Area (w = " << w << ", h=" << h << ") =" << cQ.CalculateArea(h, w);
}
#include <iostream>
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
class Circle {
private:
int radius;
public:
void SetRadius(int radius_) {
radius = radius_;
}
float CalculateArea() {
return radius * radius * 3.14;
}
};
int main() {
int radius = 0;
Circle circle;
printf("Input radius: (cm)\n");
scanf_s("%d", &radius);
circle.SetRadius(radius);
printf("Area (radius=%d) = %0.3f\n", radius, circle.CalculateArea());
}
결과:
Input radius: (cm)
3
Area (radius=3) = 28.260
생성자
• 클래스의 인스턴스가 생성될 때마다 생성자가 호출됩니다.
• 생성자의 이름은 클래스와 같으며 형식을 반환하지 않습니다.
• 클래스에 생성자가 없어도 컴파일러는 암묵적인 디폴트 생성자라고 불리는 생성자에 대한 코드를 생성합니다.
소멸자
• 클래스의 객체가 소멸될 때마다 소멸자가 호출됩니다.
• 소멸자의 이름은 같은 방식으로 정의되지만 앞에 '~'가 있습니다.
• 클래스에 소멸자가 없어도 컴파일러는 디폴트 소멸자라고 불리는 소멸자에 대한 코드를 생성합니다.
#include <iostream>
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
class Unit {
int status;
public:
Unit(int a);
~Unit();
void fly();
};
Unit::Unit(int a) : status(a) {};
Unit::~Unit() {
cout << "Unit Destructing";
status = 0;
}
void Unit::fly() {
cout << status << endl;
}
int main() {
Unit oUnit(1);
oUnit.fly();
return 0;
}
참고로 위의 생성자나 소멸자의 정의에서`
Unit::Unit(int a) {
status = a;
}
와 같은 소멸자 정의를
Unit::Unit(int a) : status(a) {};
와 같은 형태로 바꿀 수 있음
#include <iostream>
using namespace std;
class Student {
int Year;
int ID;
int Grade;
public:
Student(int Year, int iD, int grade) : Year(Year), ID(iD), Grade(grade) {}
void showData() {
cout << "Year : " << Year << ", ID: " << ID << ", Grade : " << Grade;
}
};
int main() {
Student s(2017, 100100, 1);
s.showData();
}
결과:Year : 2017, ID: 100100, Grade : 1
보다 더 직관적인 코드는
#include <iostream>
using namespace std;
class Student {
int Year;
int ID;
int Grade;
public:
Student(int Year, int iD, int grade) {
Student::Year = Year;
ID = iD;
Student::Grade = grade;
}
void showData() {
cout << "Year : " << Year << ", ID: " << ID << ", Grade : " << Grade;
}
};
int main() {
Student s(2017, 100100, 1);
s.showData();
}
위와 같을 것이다.
• 상속을 통해 다른 클래스의 관점에서 클래스를 정의할 수 있으므로 응용 프로그램을 쉽게 만들고 유지할 수 있습니다.
• 코드 재사용 및 원래 소프트웨어의 독립적 확장을 허용하는 메커니즘입니다.
#include <iostream>
using namespace std;
class NPC {
int defense;
public:
void SetDefense(int n);
int GetDefense();
};
class Grunt : public NPC {
int armor;
public:
void SetArmor(int n);
int GetArmoredDefense();
};
void NPC::SetDefense(int n) {
defense = n;
}
int NPC::GetDefense() {
return defense;
}
void Grunt::SetArmor(int n) {
armor = n;
}
int Grunt::GetArmoredDefense() {
return armor + GetDefense();
}
int main() {
Grunt oUnit;
oUnit.SetDefense(10);
oUnit.SetArmor(20);
cout << "Get Armored Defense : " << oUnit.GetArmoredDefense() << "\n";
return 0;
}
Grunt 클래스에서 NPC 클래스의 public 요소들을 가져와 사용하여 메서드를 통해 defense값을 줄 수 있다.
#include <iostream>
using namespace std;
class P {
public:
int x=10;
protected:
int y=10;
private:
int z=10;
};
class A : public P {
};
class B : protected P{
};
class C : private P{
};
int main() {
A a;
B b;
C c;
cout << a.x << endl;
cout << a.y << endl;
cout << a.z << endl;
cout << b.x << endl;
cout << b.y << endl;
cout << b.z << endl;
cout << c.x << endl;
cout << c.y << endl;
cout << c.z << endl;
}
결과:
a.x출력을 제외하면 모두 오류가 발생
이유
public으로 P를 상속 받은 a는 접근제한자가 public 이상인 x를 public변수로 그대로 받아오고, 나머지 접근 제한자는 그대로 받아짐
b는 protected보다 접근 제한 범위가 큰 x를 protected로 받아오기 때문에 모든 변수가 public이 아니므로 접근 불가
c 역시 private보다 넓은 범위인 요소들을 모두 private으로 바꿔서 상속받음
클래스는 여러 부모 클래스에서 변수 및 메서드를 상속할 수 있습니다. 클래스가 특정 클래스에서 상속될 수 있는 단일 상속과는 다릅니다.
#include <iostream>
//re: 실수
//im: 허수
using namespace std;
class Plus {
public:
void printPlus(int re1, int im1, int re2, int im2) {
cout << "Plus: " << re1 + re2 << "+" << im1 + im2 << "j" << endl;
};
};
class Minus {
public:
void printMinus(int re1, int im1, int re2, int im2) {
cout << "Minus: " << -re1 + re2 << "+" << -im1 + im2 << "j" << endl;
};
};
class Complex : public Plus, public Minus {
private:
int re;
int im;
public:
Complex() : re(0), im(0) {};
void setCom(int are, int aim) {
re = 0;
im = 0;
re += are;
im += aim;
}
void plus(int are, int aim) {
printPlus(are, aim, re, im);
}
void minus(int are, int aim) {
printMinus(are, aim, re, im);
}
};
void main() {
Complex a;
a.plus(2, 3);
a.minus(2, 3);
a.setCom(1, 1);
a.plus(2, 3);
a.minus(2, 3);
}
• 클래스에 대한 포인터는 구조체에 대한 포인터와 정확히 동일한 방식으로 작동됩니다.
• 멤버 액세스 연산자 '->'를 사용할 수 있습니다
ex)
Grunt *pUnit = new Grunt;
pUnit -> SetDefence(10);
pUnit -> SetArmor(20);
delete pUnit;
or
Grunt oUnit;
Grunt *pUnit;
pUnit = &oUnit;
pUnit->SetDefense(10);
pUnit->SetArmor(20);
void main() {
Complex *a = new Complex;
a->plus(2, 3);
a->minus(2, 3);
a->setCom(1, 1);
a->plus(2, 3);
a->minus(2, 3);
delete a;
}
• 생성자는 상속되지 않습니다.
• 상위 클래스의 생성자는 하위 생성자가 암시적으로 또는 명시적으로 호출해야 합니다.
• 상위 클래스의 생성자가 먼저 호출되고 하위 클래스의 생성자가 나중에 호출됩니다.
상속받은 자식 클래스를 호출하면 부모 클래스의 생성자를 먼저 호출하고 자신의 생성자를 호출한다.
Derived::Derived(int a) : Base(a)에서 명시적으로 생성자를 불러줘 부모클래스의 매개변수가 있는 생성자를 호출할 수 있다.
#include <iostream>
using namespace std;
class Base {
public:
Base();
Base(int a);
~Base();
};
Base::Base() {
cout << " Constructor of Base " << endl;
}
Base::Base(int a) {
cout << "Constructor of Base " << a << endl;
}
Base::~Base() {
cout << " Destructor of Base " << endl;
}
class Derived : public Base {
public:
Derived();
Derived(int a);
~Derived();
};
Derived::Derived() {
cout << " Constructor of Derived " << endl;
}
Derived::Derived(int a){
cout << " Constructor of Derived " << a << endl;
}
Derived::~Derived() {
cout << " Destructor of Derived " << endl;
}
void main() {
Derived obj1;
Derived obj2(1);
}
#include <iostream>
using namespace std;
class Student {
public:
Student() : grade(0) {}
Student(int argGrade) : grade(argGrade) {}
~Student(){}
int GetGrade() { return grade; }
private:
int grade;
};
class Calculator {
public:
Calculator() : numberOfStudent(0) {}
void AddStudent(Student argStudent);
int Sum();
private:
Student student[50];
protected:
int numberOfStudent;
};
void Calculator::AddStudent(Student argStudent) {
//student 객체 추가하기
student[numberOfStudent++] = argStudent;
}
int Calculator::Sum() {
int sum = 0;
for (int i = 0; i < numberOfStudent; i++)
sum +=student[i].GetGrade();
return sum;
}
class CalculatorEx :public Calculator {
public:
int Average() {
float average(0.0f);
average = Sum() / float(numberOfStudent);
return average;
}
};
int main() {
Student student1(30);
Student student2(90);
Student student3(100);
Student student4(50);
CalculatorEx cal;
cal.AddStudent(student1);
cal.AddStudent(student2);
cal.AddStudent(student3);
cal.AddStudent(student4);
cout << "Sum of grades : " << cal.Sum() << endl;
cout << "Average of grades : " << cal.Average() << endl;
}