목적: 클래스 객체를 표준 데이터형 사용하듯이 사용
int year = 2001; //적법한 초기화
struct thing
{
char* pn;
int m;
};
thing amabob = {"wodget", -23}; //적법한 초기화
Stock hot={"Sukie's Autos, Inc.", 200, 50.25; //컴파일 에러
-> Stock형에 일반적인 초기화 문법 적용이 안된다.
-> private접근제어로 직접 접근 불가능 [멤버 함수를 이용해야 한다.]
클래스 생성자
:객체를 성공적으로 초기화 하기 위한 멤버 함수
즉, 새로운 객체를 생성하고 그들의 데이터 멤버에 값을 대입해주는 역할을 수행
생성자의 이름 = 클래스의 이름
생성자는 리턴값이 없지만 void로 선언하지도 않는다
생성자는 데이터형을 선언하지 않는다.
객체를 선언할 때 자동호출
클래스 멤버 이름을 매개변수로 사용하지 말것
객체를 만드는 일을 끝내기 전까지는 객체가 없는 상태, 생성자 호출에 객체를 사용할 수 없다.
생성자의 선언과 정의
//디폴트 매개변수를 사용하는 생성자의 원형
Stock(const std::string& co, long n =0, double pr =0.0);
-> const std::string& co : 문자열을 지시하는 포인터, company 문자 배열 멤버를 초기화
long n , double pr: shares와 share_val 멤버를 위한 값
-> 리턴형이 없다
Stock::Stock(const std::string& co, long n, double pr)
{
std::cout << co << "를 사용하는 생성자가 호출되었습니다." << std:: endl;
company= co;
if (n < 0)
{
std::cerr << "주식 수는 음수가 될 수 없으므로, "
<< company << " shares를 0으로 설정합니다" << std::endl;
shares = 0;
}
else
shares = n;
share_val = pr;
set_tot();
}
-> acqurie() 함수에 사용한 것과 같은 코드
-> 이 경우는 객체를 선언할 때 프로그램이 자동으로 생성자를 호출
생성자 사용하기
-> 객체를 초기화 하는 2가지 방법
Stock food =Stock("World Cabbage", 250, 1.25); //명시적 호출
Stock garment("Furry Mason", 50, 2.5); //암시적 호출
Stock garment=Stock("Furry Mason", 50, 2.5); //2번을 명시적 호출
new를 사용할 때 생성자
Stock* pstock = new Stock("Electroshock Games", 18, 19.0);
-> Stock 객체를 생성, 매개변수를 통해 제공되는 값으로 그것을 초기화
-> 그 객체의 주소를 pstock 포인터를 대입 [이 경우엔 객체가 이름이 없지만 포인터로 객체에 접근 가능-> 11장]
-> 객체를 만드는 일을 끝내기 전까지는 객체가 없는 상태, 생성자 호출에 객체를 사용할 수 없다
디폴트 생성자
-> 명시적인 초기화 값을 제공하지 않을 때 객체를 생성할 때 사용하는 생성자
Stock fluffy_the_cat; //디폴트 생성자를 사용
Stock::Stock() { } //디폴트 생성자 생성
Stock::Stock(const std::string& co, long n, double pr)
Stock stock1; //생성자가 있는데 디폴트생성자가 없으면 에러 발생
디폴트 생성자의 2가지 정의 방법
Stock::Stock(const std::string& co="Error", long n=0, double pr=0.0);
// 기존의 생성자에 있는 모든 매개변수에 디폴트 값을 제공
Stock();
//함수 오버로딩을 사용하여 매개변수가 없는 또 하나의 생성자를 정의
-> 하나의 디폴트 생성자만 존재해야 한다.
Stock::Stock() //디폴트 생성자
{
company="no name";
shares=0;
share_val=0.0;
total_val=0.0;
}
Stock first; //디폴트 생성자를 암시적 호출
Stock first =Stock(); // 명시적 호출
Stock* prelief = new Stock; //암시적 호출
Stock first("Concrete Conglomerate"); //생성자 호출
Stock second(); //함수를 선언
Stock third; //디폴트 생성자를 암시적 호출
-> 디폴트가 아닌 생성자에는 암시적 호출은 불가 [디폴트 생성자의 암시적 호출에는 괄호를 사용하면 안된다.]
파괴자
: 생성자를 사용할 때 객체가 끝날 때까지 추적을 해야한다. 객체가 끝날 때 파괴자를 호출
Stock::~Stock() //클래스 파괴자
{
cout<<"안녕, "<<company<<"!\n";
}
파괴자 호출 시점
1. 프로그램이 종료될 때
2. delete를 사용할 때
3. 임시객체 생성하고 임시 객체 사용이 끝날 때
//stock10.h
#ifndef STOCK10_H_
#define STOCK10_H_
#include <string>
class Stock
{
private:
std::string company;
long shares;
double share_val;
double total_val;
void set_tot() { total_val = shares * share_val;}
public:
//두 개의 생성자
Stock(); //디폴트 생성자
Stock(const std::string& co, long n = 0, double pr = 0.0);
~Stock(); //파괴자
void buy(long num, double price);
void sell(long num, double price);
void update(double price);
void show();
};
#endif STOCK10_H_
//stock10.cpp
#include <iostream>
#include "stock10.h"
//생성자들
Stock::Stock() //디폴트 생성자
{
std::cout << "디폴트 생성자가 호출되었습니다. " <<std::endl;
company = "no name";
shares = 0;
share_val = 0.0;
total_val = 0.0;
}
Stock::Stock(const std::string& co, long n, double pr)
{
std::cout << co << "를 사용하는 생성자가 호출되었습니다." << std:: endl;
company= co;
if (n < 0)
{
std::cerr << "주식 수는 음수가 될 수 없으므로, "
<< company << " shares를 0으로 설정합니다" << std::endl;
shares = 0;
}
else
shares = n;
share_val = pr;
set_tot();
}
//클래스 파괴자
Stock::~Stock() //메시지를 출력하는 클래스 파괴자
{
std::cout << "안녕," << company << "!\n";
}
//다른 메서드들
void Stock::buy(long num, double price) //기존 보유 주식의 증가와 감소 관리
{
if (num < 0)
{
std::cout << "매입 주식 수는 음수가 될 수 없으므로, "
<< "거래가 취소되었습니다.\n";
}
else
{
shares += num;
share_val = price;
set_tot();
}
}
void Stock::sell(long num, double price) //기존 보유 주식의 감소 관리
{
using std::cout;
if (num < 0)
{
cout << "모두 주식 수는 음수가 될 수 없으므로, "
<< "거래가 취소되었습니다. \n";
}
else if (num > shares)
{
cout << "보유 주식보다 많은 주식을 매도할 수 없으므로, "
<< "거래가 취소되었습니다. \n";
}
else
{
shares -= num;
share_val = price;
set_tot();
}
}
void Stock::update(double price)
{
share_val = price;
set_tot();
}
//void Stock::show()
//{
// std::cout << "회사명: " << company
// << " 주식 수: " << shares << '\n'
// << " 주가: $" << share_val
// << " 주식 총 가치: $" << total_val << '\n';
//}
void Stock::show()
{
using std::cout;
using std::ios_base;//fmtflags가 ios_base 클래스, std 이름공간에서 정의
//set format #.##
ios_base::fmtflags orig = //orig가 긴 타입 이름이 된다.
cout.setf(ios_base::fixed, ios_base::floatfield);
std::streamsize prec = cout.precision(2);
cout << "회사명: " << company
<< " 주식 수: " << shares << '\n';
cout << " 주가: $" << share_val;
//set format to #.##
cout.precision(2);
cout << " 주식 총 가치: $" << total_val << '\n';
//restore original format
cout.setf(orig, ios_base::floatfield);
cout.precision(prec);
}
//usestok1.cpp
#include <iostream>
#include "stock10.h"
int main()
{
using std::cout;
cout << "생성자를 사용하여 새로운 객체들을 생성한다. \n";
Stock stock1("NanoSmart", 20, 12.50); //구문 1
stock1.show();
stock1.buy(15, 18.125);
Stock stock2 = Stock("Boffo Objects", 2, 2.0); //구문 2
stock2.show();
cout << "stock1을 stock2에 대입한다 \n";
stock2 = stock1;
cout << "sotck1과 stock2를 출력한다.\n";
stock1.show();
stock2.show();
cout << "생성자를 사용하여 객체를 재설정한다. \n";
stock1 = Stock("Nifty Foods", 10, 50.0); //임시 객체
cout << "갱신된 stock1: \n";
stock1.show();
cout << "프로그램을 종료합니다. \n";
return 0;
}
Stock stock2= Stock("Boffo Objects", 2, 2.0);
stock1 = Stock("Nifty Foods", 10, 50.0); //임시 객체
-> 첫 번째는 초기화를 호출하고 객체를 생성한다 임시객체를 생성할 수도 안할수도 있다
->두번째는 대입을 호출한다. 대입 구문에서 이런 방식으로 생성자를 사용하면 대입 전 항상 임시객체를 생성한다.
'Programming > C++ 2' 카테고리의 다른 글
[C++] 10장-5. 객체 배열 (0) | 2021.04.11 |
---|---|
[C++] 10장-4. this 포인터 (0) | 2021.04.11 |
[C++] 10장-2. 추상화와 클래스 (0) | 2021.04.11 |
[C++ 요약] 3장. 데이터 처리 (0) | 2021.04.09 |
[C++] 3장-4. C++ 산술 연산자 (0) | 2021.04.09 |