Encapsulation and Class

Jinyeong Choi·2024년 6월 17일

C++

목록 보기
1/5

Encapsulation

Hided Data and Codes

Definition

Encapsulation을 사용하는 이유

  • 소프트웨어가 변화에 유동적이고 flexible해진다.
  • 소프트웨어가 더 굳건하고 믿을 수 있어지고, 개발자가 더 쉽게 이해하고 관리하는 소프트웨어 개발 과정이 된다.

private

  • They can be accesssed only by other memebers of the class, and noty by any other part of program.
  • One way encapsulation is achieved
  • C++'s default mode

public

  • Member functions or member variables should be declared after the public keyword.
  • All variables or functions defined after the public specifier are accessible by all other functions in your program.

auto

  • auto keyword allows the compiler to automatically deduce the type of a variable if it is initialized when it is declared.
  • auto keyword may not be used without an accompanying initialization. 변수의 자료형을 유추할 수 없을 때 자료형 선언을 auto로 하면 안된다.

Class

Definition

class C {
	int n;
public:
	S(int); // Constructor Declaration
    S() {n=0;} // Constructor Definition
};

S::S(int) {
	n=1;
}

int main() {
	S s; // calls S::S()
    S s2(10); // calls S::S(int)
}

위의 내용은 클래스를 정의하는 방법이다. 다양한 방법으로 클래스의 객체를 만들고 다양한 형태의 생성자로 표현할 수 있다.

Initialization List

S():n(0) {}

Static Member Data and Functions

  • C++ uses the static keyword within a class to specify that all objects of that class share a field
  • 클래스의 모든 객체들이 공유하고 있는 변수들이나 상수들이 있는 것이 편리할 때도 있다. 글로벌 변수와 상수는 동작은 하겠지만 특정 클래스에 묶여있는 것은 아니다. 그렇기에 static으로 선언된 변수나 상수가 필요한 것.

Classes vs. Structures

  • Struct is derived from C language.
  • Similar statement with Class definition but every member is public by default.
  • Struct can contain methods and constructors.
#include <iostream>
using namespace std;

class Point {
	double x;
	double y;

public:
	Point();
	Point(int x, int y);
	void setPoint(int x, int y);
	int getX() const;
	int getY() const;
	Point operator+(const Point& point);
	Point& operator=(const Point& point);
};

Point::Point() {
	x = y = 0;
}

Point::Point(int x_, int y_) {
	x = x_;
	y = y_;
}

void Point::setPoint(int x_, int y_) {
	this->x = x_;
	this->y = y_;
}

int Point::getX() const {
	return x;
}

int Point::getY() const {
	return y;
}

Point Point::operator+(const Point& point) {
	Point hello;
	hello.x = this->x + point.x;
	hello.y = this->y + point.y;
	return hello;
}

Point& Point::operator=(const Point& p) {
	this->x = p.x;
	this->y = p.y;
	return *this;
}

std::ostream& operator<<(std::ostream& os, const Point& point) {
	return os << point.getX() << " " << point.getY() << '\n';
}

int main() {
	Point* pP1, * pP2;

	pP1 = new Point;
	pP2 = new Point(1, 2);
  
	pP1->setPoint(10, 20);
	*pP2 = *pP2 + *pP1;

	cout << "x: " << pP1->getX() << ", y: " << pP1->getY() << '\n';
	cout << *pP2 << '\n';

	delete pP1;
	delete pP2;
}

friend function

  • It can be advantageous to design a class that grants special access to some precisely specified functions or classes of objects outside of the class.

Inheritance

is-relationship

  • the Derived Class is a Base Class
    ** a Derived Class has all data and functions of a Base Class

  • the Base Class is not a Derived Class
    ** a Base Class has no whole data and functions of a Derived Class.

#include <iostream>
using namespace std;

class Base {
public:
	void f();
};

void Base::f() {
	cout << "in function 'Base::f()'\n";
}

class Derived : public Base {
public:
	void g();
};

void Derived::g() {
	cout << "in function 'Derived::g()'\n";
}

int main() {
	Base b;
	Derived d;

	d.f(); //in function 'Base::f()'
	d.g(); //in function 'Derived::g()'
}
#include <iostream>
#include <string>
using namespace std;

class Text {
	string text;
public:
	Text(const string& t) : text(t) {}

	virtual string get() const {
		return text;
	}

	virtual void append(const string& extra) {
		text += extra;
	}
};

class FancyText : public Text {
	string left_bracket;
	string right_bracket;
	string connector;
public:
	FancyText(const string& t, const string& left, const string& right, const string& conn)
		: Text(t), left_bracket(left), right_bracket(right), connector(conn) {}

	string get() const override{
		return left_bracket + Text::get() + right_bracket;
	}

	void append(const string& extra) override {
		Text::append(connector + extra);
	}
};

class Fixed : public Text {
public:
	Fixed() : Text("Fixed") {}
	void append(const string&) override {}
};

int main() {
	Text t1("plain");
	FancyText t2("fancy", "<<", ">>", "***");
	Fixed t3;

	cout << t1.get() << endl;
	cout << t2.get() << endl;
	cout << t3.get() << endl;
	cout << endl;

	t1.append("A");
	t2.append("A");
	t3.append("A");
	cout << t1.get() << endl;
	cout << t2.get() << endl;
	cout << t3.get() << endl;
	cout << endl;

	t1.append("B");
	t2.append("B");
	t3.append("B");
	cout << t1.get() << endl;
	cout << t2.get() << endl;
	cout << t3.get() << endl;
	cout << endl;
}

Inheritance Type

Access Protection of Base Class

class Base {

};

class Derived : {TYPE} Base {

};
#include <iostream>
using namespace std;

class Base {
public:
	void f();
};

void Base::f() {
	cout << "in function 'Base::f()'\n";
}

class Derived : private Base {
public:
	void g();
};

void Derived::g() {
	Base::f();
	cout << "in function 'Drived::g()'\n";
}

int main() {
	Base b;
	Derived d;
	b.f(); 
	d.g();
}

private하게 상속받았을 경우, Derived 클래스의 객체는 Base 클래스의 함수를 불러오는 순간 compile Error가 발생한다. 아래와 같은 방식으로 Derived 클래스의 객체가 Derived 클래스 안에 있는 함수를 불러오는 것은 아무런 문제가 발생하지 않는다.
위와 같은 방식은 Derived::g()를 호출했을 때에 Base의 f()도 호출되게 되는데, 이 부분은 private function f() can be invoked privately.

class Derived : private Base {
public:
	void g();
};

void Derived::g() {
	cout << "in function 'Drived::g()'\n";
}

int main() {
	Base b;
	Derived d;
	b.f(); 
	d.g();
}

C++에서는 다른언어들과는 다르게 여러 개의 Base Class로부터 상속받을 수 있다. 이것을 우리는 Multiple Inheritance라고 부른다.

class Derived : public Base1, public Base2, public Base3 {
};

Reusability and Specialization

  • 상속은 개발자들이 이미 존재하는 클래스를 가져와 새로운 클래스를 만들고 새로운 클래스에 enhanced behavior or different behavior를 제공하도록 하게 한다.
  • 개발자들은 상속받은 클래스로 Base class의 코드를 그대로 복사하는 것이 아니라 기존에 존재하는 코드에 영향을 줄 뿐.

Function Overriding and Overloading

Function Overriding

  • Specifies that a virtual function overrides[=replace, re-define] another virtual function.
  • 함수 오버라이딩은 상속받을 때의 Base Class에서 먼저 정의된 virtual 함수를 가져와 override라는 키워드와 함께 Derived class에서 재정의하는 것을 의미한다.
virtual:

The virtual specifier indicates that the designer of the Base class intends for derived classes to be able to customize the behavior of the virtual methods.

override:

The exact behavior of these methods (in the Derived class) will be different in some way from their implementation in the Base class.

Function Overloading

  • C++ allows you to specify more than one definition for a function name or an operator in the same scope, which is called function overloading and operator overloading.
  • 함수 오버로딩은 선언된 함수의 이름은 같으나, parameter의 수가 다르거나, 자료형이 다르거나, 순서가 다른 것과 같이 arguments와 definition의 내용이 명백히 달라야한다.
  • 만약, 매개변수 목록이 동일한 함수가 중복 정의되면 컴팓일러는 어떤 함수를 호출해야 하는지 제대로 알 수 없기 때문에 컴파일 에러 발생!

Static Binding and Dynamic Binding

Binding이란 프로그램 소스에 쓰인 각종 내부 요소, 이름 식별자들에 대해 값 또는 속성을 확정한 과정을 의미.
프로그램을 위한 변수, 함수들은 그 내용을 저장할 메모리를 할당해야 한다. 그 이전에 변수 및 함수의 타입과 값이 결정되어야 하는데, 이 타입과 값을 결정하는 과정을 의미.

Static Binding

Static Binding(정적 바인딩)은 변수 및 함수가 컴파일 시점에 이루어지는 바인딩을 뜻함.
소스 상에 명시적으로 타입과 그 타입의 변수명을 선언하는 것.
Static Binding is relatively easy to understand: the method to execute depends on the declared type of the variable upon which the method is invoked.
Static Binding의 장점

  • 컴파일 시 타입에 대한 정보가 결정되므로 속도가 빠르다
  • 타입 에러로 인한 문제를 조기에 발견할 수 있어 안정적이다
    단점
  • 컴파일 시 결정이 되고 그 이후 변경 불가
#include <iostream>
using namespace std;

class Base {
public:
	void f() {
		cout << "in function 'Base::f()'\n";
	}

	virtual void vf() {
		cout << "in function 'Base::vf()'\n";
	}
};

class Derived : public Base {
public:
	void f() {
		cout << "in function 'Derived::f()'\n";
	}

	void vf() override {
		cout << "in function 'Derived::vf()'\n";
	}
};

int main() {
	Base b;
	Derived d;

	b.f(); //in function 'Base::f()'
	b.vf(); //in function 'Base::vf()'
	d.f(); //in function 'Derived::f()'
	d.vf(); //in function 'Derived::vf()'
}

Dynamic Binding

Dynamic Binding(동적 바인딩)이란 바인딩 과정이 실행 도중 이루어지는 것.

#include <iostream>
using namespace std;

class Base {
public:
	void f() {
		cout << "in function 'Base::f()'\n";
	}

	virtual void vf() {
		cout << "in function 'Base::vf()'\n";
	}
};

class Derived : public Base {
public:
	void f() {
		cout << "in function 'Derived::f()'\n";
	}

	void vf() override {
		cout << "in function 'Derived::vf()'\n";
	}
};

int main() {
	Base* p;
	Base b;
	Derived d;

	p = &b;
	p->f(); //in function 'Base::f()'
	p->vf(); //in function 'Base::vf()'

	p = &d;
	p->f(); //in function 'Base::f()'
	p->vf(); //in function 'Derived::vf()'
}

In the case of virtual method invoked via a pointer, the running program, not the compiler, determines exactly which code to execute. The process is known as dynamic binding or late binding.
Dynamic Binding의 장점

  • 실행도중 필요한 객체의 함수를 호출함으로써 유연성을 가지고 있음
    단점
  • 변수의 예상치 못한 타입으로 안정성 저하

Polymorphism

profile
Hang in there

0개의 댓글