-
C++프로그래밍 언어/클래스 2009. 1. 1. 01:12상속시 생성자, 소멸자, 대입 연산자 등은 제외된다.
가상 소멸자의 가상성(?)은 상속
실행할 가상(virtual) 함수를 런타임에 선택하는 것은 그 함수가 레퍼런스나 포인터를 통해 호출될 때에만 가능하다.
그렇지 않으면 정적 바인딩
가상 함수는 프로그램에서 그 함수를 호출하는지 여부에 상관 없이, 꼭 정의되어야 한다.
파생 클래스에서 오버라이드하는 함수의 타입은 기본 클래스의 그 가상 함수의 타입과 같아야 한다.
단, 반환 타입은 예외
반드시 초기화 리스트로 멤버를 초기화해야 하는 경우
상속받은 멤버를 초기화
포함된 객체 초기화
상수 멤버 초기화
레퍼런스 멤버 초기화
만약 클래스가 아무 생성자라도 명시적으로 정의했다면, 컴파일러는 그 클래스에 대한 디폴트 생성자를 자동으로 만들어 주지 않는다.
eg. Position There[3]={Position(1,2,'x'),Position(3,4,'y'),Position(5,6,'z')};
디폴트 생성자를 사용하는 클래스의 데이터 멤버로 사용되기 위해서는, 그 데이터 타입 자체로 디폴트 생성자를 제공해야 한다.
컴파일러가 자동으로 만들어주는 복사 생성자와 대입 연산자는 클래스의 데이터 멤버들을 단순 복사(얕은 복사)
rule of three
만약 클래스에 소멸자가 필요하면(생성자 네에서 리소스를 할당), 십중팔구 대입 연산자 뿐만 아니라, 복사생성자도 필요
복사 생성자
자신과 같은 타입의 다른 객체에 대한 레퍼런스를 전달받아 이 레퍼런스로부터 자신을 초기화한다
객체가 함수의 인수로 전달될 때
암묵적 복사 : 함수의 인자(by value), 함수의 리턴값
명시적 복사 : 초기화
(타입 )변환 생성자(Conversion Constructor)
다른 타입(기본 타입 포함)으로부터 객체를 만드는 생성자이며 인수를 하나만 취한다
r value에서 타입 변환을 위한 임시 객체 생성시 등
변환 생성자는 편리하기도 하지만 클래스(타입)간의 구분을 모호하게 만든다.
explicit로 지정된 생성자는 암시적인 형 변환에 사용할 수 없도록 금지된다.
사용자 정의 변환
단일 인자를 갖는 생성자
explicit 키워드
(타입 )변환 연산자 // 변환 함수?
목표 타입에 생성자를 추가하는 것이 불가능
객체으로부터 다른 타입의(기본 타입 포함) 객체 값을 반환
클래스의 멤버로 정의
.operator {타입이름} () { .. }
cf. int operator() (int a,int b,int c,int d) { return a+b+c+d; } // 리턴타입 operator{연산자} (인수 목록) { 함수 본체; }
암시적 변환이 문제가 된다면 변환 함수를 만들지 말고 명시적인 함수
연산자 오버로딩
대입 연산자
자신과 같은 타입(??)의 다른 객체를 대입받을 때 사용하는 연산자
안전한 대입 연산자 // sutter
대입 연산자가 복사 생성자를 호출하도록 한다.
예외가 발생했을 때 객체의 생성이 불완전한 상태로 끝나는 것을 방지할 수 있다. //??
인덱스 연산자
입출력 연산자
복사 생성 및 대입 금지 // 싱글톤?
복사 생성자와 대입 연산자를 선언하되 둘 다 private 영역에 둔다.
외부에서 불가능한 동작을 시도하면 컴파일러가 막아주고 내부에서 엉뚱한 짓을 하려면 링커가 막아준다.
순수 가상 함수
virtual 메커니즘이 동작하지 않는 환경
(1) 기본 클래스의 생성자와 소멸자 내
(2) 기본 클래스의 포인터나 레퍼런스가 아니라 기본 클래스의 객체를 사용
RTTI
type_info 클래스
#include <typeinfo>
typeid 연산자
.name()
if ( typeid( *ps ) == typeid( Fibonacci ))
{
Fibonacci *pf = static_cast<Fibonacci *>( ps );
pf->gen_elements( 64 );
}
or
if ( Fibonacci *pf = dynamic_cast<Fibonacci *>( ps ))
pf->gen_elements(64);
새로운 클래스의 생성
복사 생성자
Matrix::Matrix( const Matrix &rhs )
{
...}
template<class T> void swap(T& a, T& b)
{
T copy(a);
a = b;
b = copy;
}
void apImage::swap(apImage& src)
{
::swap(width_, src.width_);
::swap(height_, src.height_);
::swap(pixels_, src.pixels_);
}
apImage& apImage::operator =(const apImage& src)
{
apImage temp(src);
swap(temp);
return *this;
}
/*
or
Matrix& matrix::
operator=( const Matrix &rhs )
{
if ( this != &rhs )
{
...}
return *this;
}
*/
iostream 연산자 오버로딩
ostream& operator<<( ostream &os, const Triangular &rhs )
{
...
return os;
}
istream& operator>>( istream &is, Triangular &rhs )
{
...
return is;
}
제네릭 핸들 클래스(스마트 포인터??)
#ifndef GUARD_Ptr_h
#define GUARD_Ptr_h
#include <cstddef>
#include <stdexcept>
template <class T> class Ptr {
public:
// new member to copy the object conditionally when needed
void make_unique() {
if (*refptr != 1) {
--*refptr;
refptr = new size_t(1);
p = p? clone(p): 0;
}
}
// the rest of the class looks like `Ref_handle' except for its name
Ptr(): p(0), refptr(new size_t(1)) { }
Ptr(T* t): p(t), refptr(new size_t(1)) { }
Ptr(const Ptr& h): p(h.p), refptr(h.refptr) { ++*refptr; }
Ptr& operator=(const Ptr&);
~Ptr();
operator bool() const { return p; }
T& operator*() const;
T* operator->() const;
private:
T* p;
std::size_t* refptr;
};
template <class T> T* clone(const T* tp)
{
return tp->clone();
}
template<class T>
T& Ptr<T>::operator*() const { if (p) return *p; throw std::runtime_error("unbound Ptr"); }
template<class T>
T* Ptr<T>::operator->() const { if (p) return p; throw std::runtime_error("unbound Ptr"); }
template<class T>
Ptr<T>& Ptr<T>::operator=(const Ptr& rhs)
{
++*rhs.refptr;
// \f2free the lhs, destroying pointers if appropriate\fP
if (--*refptr == 0) {
delete refptr;
delete p;
}
// \f2copy in values from the right-hand side\fP
refptr = rhs.refptr;
p = rhs.p;
return *this;
}
template<class T> Ptr<T>::~Ptr()
{
if (--*refptr == 0) {
delete refptr;
delete p;
}
}
#endif
#ifndef GUARD_Handle_h
#define GUARD_Handle_h
template <class T> class Handle {
public:
Handle(): p(0) { }
Handle(const Handle& s): p(0) { if (s.p) p = s.p->clone(); }
Handle& operator=(const Handle&);
~Handle() { delete p; }
Handle(T* t): p(t) { }
operator bool() const { return p; }
T& operator*() const;
T* operator->() const;
private:
T* p;
};
#include <stdexcept>
using std::runtime_error;
template <class T>
Handle<T>& Handle<T>::operator=(const Handle& rhs)
{
if (&rhs != this) {
delete p;
p = rhs.p ? rhs.p->clone() : 0;
}
return *this;
}
template <class T>
T& Handle<T>::operator*() const
{
if (p)
return *p;
throw runtime_error("unbound Handle");
}
template <class T>
T* Handle<T>::operator->() const
{
if (p)
return p;
throw runtime_error("unbound Handle");
}
#endif
#ifndef Ref_handle_h
#define Ref_handle_h
#include <cstddef>
#include <stdexcept>
template <class T> class Ref_handle {
public:
// manage reference count as well as pointer
Ref_handle(): p(0), refptr(new size_t(1)) { }
Ref_handle(T* t): p(t), refptr(new size_t(1)) { }
Ref_handle(const Ref_handle& h): p(h.p), refptr(h.refptr) {
++*refptr;
}
Ref_handle& operator=(const Ref_handle&);
~Ref_handle();
operator bool() const { return p; }
T& operator*() const {
if (p)
return *p;
throw std::runtime_error("unbound Ref_handle");
}
T* operator->() const {
if (p)
return p;
throw std::runtime_error("unbound Ref_handle");
}
private:
T* p;
std::size_t* refptr;
};
template <class T>
Ref_handle<T>& Ref_handle<T>::operator=(const Ref_handle& rhs)
{
++*rhs.refptr;
// free the left-hand side, destroying pointers if appropriate
if (--*refptr == 0) {
delete refptr;
delete p;
}
// copy in values from the right-hand side
refptr = rhs.refptr;
p = rhs.p;
return *this;
}
template <class T> Ref_handle<T>::~Ref_handle()
{
if (--*refptr == 0) {
delete refptr;
delete p;
}
}
#endif
#ifndef GUARD_Str_h
#define GUARD_Str_h
#include <algorithm>
#include <iostream>
#include "Ptr.h"
#include "Vec.h"
template<>
Vec<char>* clone(const Vec<char>*);
// does this version work?
class Str {
friend std::istream& operator>>(std::istream&, Str&);
friend std::istream& getline(std::istream&, Str&);
public:
Str& operator+=(const Str& s) {
data.make_unique();
std::copy(s.data->begin(), s.data->end(),
std::back_inserter(*data));
return *this;
}
// interface as before
typedef Vec<char>::size_type size_type;
// reimplement constructors to create `Ptr's
Str(): data(new Vec<char>) { }
Str(const char* cp): data(new Vec<char>) {
std::copy(cp, cp + std::strlen(cp),
std::back_inserter(*data));
}
Str(size_type n, char c): data(new Vec<char>(n, c)) { }
template <class In> Str(In i, In j): data(new Vec<char>) {
std::copy(i, j, std::back_inserter(*data));
}
// call `make_unique' as necessary
char& operator[](size_type i) {
data.make_unique();
return (*data)[i];
}
const char& operator[](size_type i) const { return (*data)[i]; }
size_type size() const { return data->size(); }
typedef char* iterator;
typedef const char* const_iterator;
iterator begin() { return data->begin(); }
const_iterator begin() const { return data->begin(); }
iterator end() { return data->end(); }
const_iterator end() const { return data->end(); }
private:
// store a `Ptr' to a `vector'
Ptr< Vec<char> > data;
};
std::ostream& operator<<(std::ostream&, const Str&);
Str operator+(const Str&, const Str&);
inline bool operator<(const Str& lhs, const Str& rhs)
{
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
inline bool operator>(const Str& lhs, const Str& rhs)
{
return std::lexicographical_compare(rhs.begin(), rhs.end(), lhs.begin(), lhs.end());
}
inline bool operator<=(const Str& lhs, const Str& rhs)
{
return !std::lexicographical_compare(rhs.begin(), rhs.end(), lhs.begin(), lhs.end());
}
inline bool operator>=(const Str& lhs, const Str& rhs)
{
return !std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
inline bool operator==(const Str& lhs, const Str& rhs)
{
return lhs.size() == rhs.size() &&
std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
inline bool operator!=(const Str& lhs, const Str& rhs)
{
return !(lhs == rhs);
}
#endif
#include <cctype>
#include <iostream>
#include <iterator>
using std::isspace;
#include "Str.h"
using std::istream;
using std::istream_iterator;
using std::ostream;
ostream& operator<<(ostream& os, const Str& s)
{
for (Str::size_type i = 0; i != s.size(); ++i)
os << s[i];
return os;
}
istream& operator>>(istream& is, Str& s)
{
// obliterate existing value(s)
s.data->clear();
// read and discard leading whitespace
char c;
while (is.get(c) && isspace(c))
; // nothing to do, except testing the condition
// if still something to read, do so until next whitespace character
if (is) {
do s.data->push_back(c); // `\f(BIcompile error!, data' is `private'
while (is.get(c) && !isspace(c));
// if we read whitespace, then put it back on the stream
if (is)
is.unget();
}
return is;
}
Str operator+(const Str& s, const Str& t)
{
Str r = s;
r += t;
return r;
}
istream& getline(istream&is, Str& s)
{
s.data->clear();
char c;
while (is.get(c) && isspace(c))
; // \f2nothing to do, except testing the condition\fP
// \f2if still something to read, do so until next whitespace character\fP
if (is) {
do s.data->push_back(c);
while (is.get(c) && c != '\n');
// \f2if we read whitespace, then put it back on the stream\fP
if (is)
is.unget();
}
return is;
}
#ifndef VEC_H
#define VEC_H
#include <algorithm>
#include <cstddef>
#include <memory>
using std::max;
template <class T> class Vec {
public:
typedef T* iterator;
typedef const T* const_iterator;
typedef size_t size_type;
typedef T value_type;
typedef T& reference;
typedef const T& const_reference;
Vec() { create(); }
explicit Vec(size_type n, const T& t = T()) { create(n, t); }
Vec(const Vec& v) { create(v.begin(), v.end()); }
Vec& operator=(const Vec&);
~Vec() { uncreate(); }
T& operator[](size_type i) { return data[i]; }
const T& operator[](size_type i) const { return data[i]; }
void push_back(const T& t) {
if (avail == limit)
grow();
unchecked_append(t);
}
size_type size() const { return avail - data; }
iterator begin() { return data; }
const_iterator begin() const { return data; }
iterator end() { return avail; }
const_iterator end() const { return avail; }
void clear() { uncreate(); }
bool empty() const { return data == avail; }
private:
iterator data; // first element in the `Vec'
iterator avail; // (one past) the last element in the `Vec'
iterator limit; // (one past) the allocated memory
// facilities for memory allocation
std::allocator<T> alloc; // object to handle memory allocation
// allocate and initialize the underlying array
void create();
void create(size_type, const T&);
void create(const_iterator, const_iterator);
// destroy the elements in the array and free the memory
void uncreate();
// support functions for `push_back'
void grow();
void unchecked_append(const T&);
};
template <class T> void Vec<T>::create()
{
data = avail = limit = 0;
}
template <class T> void Vec<T>::create(size_type n, const T& val)
{
data = alloc.allocate(n);
limit = avail = data + n;
std::uninitialized_fill(data, limit, val);
}
template <class T>
void Vec<T>::create(const_iterator i, const_iterator j)
{
data = alloc.allocate(j - i);
limit = avail = std::uninitialized_copy(i, j, data);
}
template <class T> void Vec<T>::uncreate()
{
if (data) {
// destroy (in reverse order) the elements that were constructed
iterator it = avail;
while (it != data)
alloc.destroy(--it);
// return all the space that was allocated
alloc.deallocate(data, limit - data);
}
// reset pointers to indicate that the `Vec' is empty again
data = limit = avail = 0;
}
template <class T> void Vec<T>::grow()
{
// when growing, allocate twice as much space as currently in use
size_type new_size = max(2 * (limit - data), ptrdiff_t(1));
// allocate new space and copy existing elements to the new space
iterator new_data = alloc.allocate(new_size);
iterator new_avail = std::uninitialized_copy(data, avail, new_data);
// return the old space
uncreate();
// reset pointers to point to the newly allocated space
data = new_data;
avail = new_avail;
limit = data + new_size;
}
// assumes `avail' points at allocated, but uninitialized space
template <class T> void Vec<T>::unchecked_append(const T& val)
{
alloc.construct(avail++, val);
}
template <class T>
Vec<T>& Vec<T>::operator=(const Vec& rhs)
{
// check for self-assignment
if (&rhs != this) {
// free the array in the left-hand side
uncreate();
// copy elements from the right-hand to the left-hand side
create(rhs.begin(), rhs.end());
}
return *this;
}
#endif
#include "Vec.h"
template <class T> T* clone(const T* tp);
// the key to making `Ptr< Vec<char> >' work
template<>
Vec<char>* clone(const Vec<char>* vp)
{
return new Vec<char>(*vp);
}
#ifndef STR_H
#define STR_H
#include <algorithm>
#include <cstring>
#include <cctype>
using std::isspace;
#include "Vec.h"
class Str {
// input operator implemented in 12.3.2/216
friend std::istream& operator>>(std::istream&, Str&);
friend std::istream& getline(std::istream&, Str&);
public:
Str& operator+=(const Str& s) {
std::copy(s.data.begin(), s.data.end(),
std::back_inserter(data));
return *this;
}
typedef Vec<char>::size_type size_type;
Str() { }
Str(size_type n, char c): data(n, c) { }
Str(const char* cp) {
std::copy(cp, cp + std::strlen(cp), std::back_inserter(data));
}
template <class In> Str(In i, In j) {
std::copy(i, j, std::back_inserter(data));
}
char& operator[](size_type i) { return data[i]; }
const char& operator[](size_type i) const { return data[i]; }
size_type size() const { return data.size(); }
typedef char* iterator;
typedef const char* const_iterator;
iterator begin() { return data.begin(); }
const_iterator begin() const { return data.begin(); }
iterator end() { return data.end(); }
const_iterator end() const { return data.end(); }
private:
Vec<char> data;
};
std::ostream& operator<<(std::ostream&, const Str&);
Str operator+(const Str&, const Str&);
inline bool operator<(const Str& lhs, const Str& rhs)
{
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
inline bool operator>(const Str& lhs, const Str& rhs)
{
return std::lexicographical_compare(rhs.begin(), rhs.end(), lhs.begin(), lhs.end());
}
inline bool operator<=(const Str& lhs, const Str& rhs)
{
return !std::lexicographical_compare(rhs.begin(), rhs.end(), lhs.begin(), lhs.end());
}
inline bool operator>=(const Str& lhs, const Str& rhs)
{
return !std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
inline bool operator==(const Str& lhs, const Str& rhs)
{
return lhs.size() == rhs.size() &&
std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
inline bool operator!=(const Str& lhs, const Str& rhs)
{
return !(lhs == rhs);
}
#endif
#include <cctype>
#include <iostream>
#include <iterator>
using std::isspace;
#endif
#include "Str.h"
using std::istream;
using std::istream_iterator;
using std::ostream;
ostream& operator<<(ostream& os, const Str& s)
{
for (Str::size_type i = 0; i != s.size(); ++i)
os << s[i];
return os;
}
istream& operator>>(istream& is, Str& s)
{
// obliterate existing value(s)
s.data.clear();
// read and discard leading whitespace
char c;
while (is.get(c) && isspace(c))
; // nothing to do, except testing the condition
// if still something to read, do so until next whitespace character
if (is) {
do s.data.push_back(c); // `\f(BIcompile error!, data' is `private'
while (is.get(c) && !isspace(c));
// if we read whitespace, then put it back on the stream
if (is)
is.unget();
}
return is;
}
Str operator+(const Str& s, const Str& t)
{
Str r = s;
r += t;
return r;
}
istream& getline(istream&is, Str& s)
{
s.data.clear();
char c;
while (is.get(c) && isspace(c))
; // \f2nothing to do, except testing the condition\fP
// \f2if still something to read, do so until next whitespace character\fP
if (is) {
do s.data.push_back(c);
while (is.get(c) && c != '\n');
// \f2if we read whitespace, then put it back on the stream\fP
if (is)
is.unget();
}
return is;
}
#ifndef VEC_H
#define VEC_H
#include <algorithm>
#include <cstddef>
#include <memory>
using std::max;
template <class T> class Vec {
public:
typedef T* iterator;
typedef const T* const_iterator;
typedef size_t size_type;
typedef T value_type;
typedef T& reference;
typedef const T& const_reference;
Vec() { create(); }
explicit Vec(size_type n, const T& t = T()) { create(n, t); }
Vec(const Vec& v) { create(v.begin(), v.end()); }
Vec& operator=(const Vec&);
~Vec() { uncreate(); }
T& operator[](size_type i) { return data[i]; }
const T& operator[](size_type i) const { return data[i]; }
void push_back(const T& t) {
if (avail == limit)
grow();
unchecked_append(t);
}
size_type size() const { return avail - data; }
iterator begin() { return data; }
const_iterator begin() const { return data; }
iterator end() { return avail; }
const_iterator end() const { return avail; }
void clear() { uncreate(); }
bool empty() const { return data == avail; }
private:
iterator data; // first element in the `Vec'
iterator avail; // (one past) the last element in the `Vec'
iterator limit; // (one past) the allocated memory
// facilities for memory allocation
std::allocator<T> alloc; // object to handle memory allocation
// allocate and initialize the underlying array
void create();
void create(size_type, const T&);
void create(const_iterator, const_iterator);
// destroy the elements in the array and free the memory
void uncreate();
// support functions for `push_back'
void grow();
void unchecked_append(const T&);
};
template <class T> void Vec<T>::create()
{
data = avail = limit = 0;
}
template <class T> void Vec<T>::create(size_type n, const T& val)
{
data = alloc.allocate(n);
limit = avail = data + n;
std::uninitialized_fill(data, limit, val);
}
template <class T>
void Vec<T>::create(const_iterator i, const_iterator j)
{
data = alloc.allocate(j - i);
limit = avail = std::uninitialized_copy(i, j, data);
}
template <class T> void Vec<T>::uncreate()
{
if (data) {
// destroy (in reverse order) the elements that were constructed
iterator it = avail;
while (it != data)
alloc.destroy(--it);
// return all the space that was allocated
alloc.deallocate(data, limit - data);
}
// reset pointers to indicate that the `Vec' is empty again
data = limit = avail = 0;
}
template <class T> void Vec<T>::grow()
{
// when growing, allocate twice as much space as currently in use
size_type new_size = max(2 * (limit - data), ptrdiff_t(1));
// allocate new space and copy existing elements to the new space
iterator new_data = alloc.allocate(new_size);
iterator new_avail = std::uninitialized_copy(data, avail, new_data);
// return the old space
uncreate();
// reset pointers to point to the newly allocated space
data = new_data;
avail = new_avail;
limit = data + new_size;
}
// assumes `avail' points at allocated, but uninitialized space
template <class T> void Vec<T>::unchecked_append(const T& val)
{
alloc.construct(avail++, val);
}
template <class T>
Vec<T>& Vec<T>::operator=(const Vec& rhs)
{
// check for self-assignment
if (&rhs != this) {
// free the array in the left-hand side
uncreate();
// copy elements from the right-hand to the left-hand side
create(rhs.begin(), rhs.end());
}
return *this;
}
#endif
#ifndef GUARD_Core_h
#define GUARD_Core_h
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
class Core {
public:
Core(): midterm(0), final(0) { }
Core(std::istream& is) { read(is); }
std::string name() const;
virtual std::istream& read(std::istream&);
virtual double grade() const;
virtual ~Core() { }
protected:
// accessible to derived classes
std::istream& read_common(std::istream&);
double midterm, final;
std::vector<double> homework;
public:
virtual Core* clone() const { return new Core(*this); }
private:
// accessible only to `Core'
std::string n;
friend class Student_info;
};
class Grad: public Core {
public:
Grad(): thesis(0) { }
Grad(std::istream& is) { read(is); }
double grade() const;
std::istream& read(std::istream&);
private:
double thesis;
Grad* clone() const { return new Grad(*this); }
};
bool compare(const Core&, const Core&);
bool compare_Core_ptrs(const Core* cp1, const Core* cp2);
#endif
#include <algorithm>
using std::min;
#include "Core.h"
#include "grade.h"
using std::istream;
using std::string;
using std::vector;
std::istream& read_hw(std::istream& in, std::vector<double>& hw);
string Core::name() const { return n; }
double Core::grade() const
{
return ::grade(midterm, final, homework);
}
istream& Core::read_common(istream& in)
{
// read and store the student's name and exam grades
in >> n >> midterm >> final;
return in;
}
istream& Core::read(istream& in)
{
read_common(in);
read_hw(in, homework);
return in;
}
istream& Grad::read(istream& in)
{
read_common(in);
in >> thesis;
read_hw(in, homework);
return in;
}
double Grad::grade() const
{
return min(Core::grade(), thesis);
}
bool compare(const Core& c1, const Core& c2)
{
return c1.name() < c2.name();
}
bool compare_Core_ptrs(const Core* cp1, const Core* cp2)
{
return compare(*cp1, *cp2);
}
#include <algorithm>
#include <ios>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <vector>
#include "Handle.h"
#include "Student_info.h"
using std::cin;
using std::cout;
using std::domain_error;
using std::endl;
using std::sort;
using std::streamsize;
using std::setprecision;
using std::setw;
using std::string;
using std::vector;
#ifdef _MSC_VER
#include "../minmax.h"
#else
using std::max;
#endif
bool compare_Core_handles(const Handle<Core>& lhs, const Handle<Core>& rhs) {
return compare(*lhs, *rhs);
}
int main()
{
vector< Handle<Core> > students;
Handle<Core> record;
char ch;
string::size_type maxlen = 0;
// read and store the data
while (cin >> ch) {
if (ch == 'U')
record = new Core; // allocate a `Core' object
else
record = new Grad; // allocate a `Grad' object
record->read(cin); // `Handle<T>::->', then `virtual' call to `read'
maxlen = max(maxlen, record->name().size()); // `Handle<T>::->'
students.push_back(record);
}
// `compare' must be rewritten to work on `const Handle<Core>&'
sort(students.begin(), students.end(), compare_Core_handles);
// write the names and grades
for (vector< Handle<Core> >::size_type i = 0;
i != students.size(); ++i) {
// `students[i]' is a `Handle', which we dereference to call the functions
cout << students[i]->name()
<< string(maxlen + 1 - students[i]->name().size(), ' ');
try {
double final_grade = students[i]->grade();
streamsize prec = cout.precision();
cout << setprecision(3) << final_grade
<< setprecision(prec) << endl;
} catch (domain_error e) {
cout << e.what() << endl;
}
// no `delete' statement
}
return 0;
}
핸들 클래스
#ifndef GUARD_Core_h
#define GUARD_Core_h
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
class Core {
public:
Core(): midterm(0), final(0) { }
Core(std::istream& is) { read(is); }
std::string name() const;
virtual std::istream& read(std::istream&);
virtual double grade() const;
virtual ~Core() { }
protected:
// accessible to derived classes
std::istream& read_common(std::istream&);
double midterm, final;
std::vector<double> homework;
virtual Core* clone() const { return new Core(*this); }
private:
// accessible only to `Core'
std::string n;
friend class Student_info;
};
class Grad: public Core {
public:
Grad(): thesis(0) { }
Grad(std::istream& is) { read(is); }
double grade() const;
std::istream& read(std::istream&);
private:
double thesis;
Grad* clone() const { return new Grad(*this); }
};
bool compare(const Core&, const Core&);
bool compare_Core_ptrs(const Core* cp1, const Core* cp2);
#endif
#include <algorithm>
using std::min;
#include "Core.h"
#include "grade.h"
using std::istream;
using std::string;
using std::vector;
std::istream& read_hw(std::istream& in, std::vector<double>& hw);
string Core::name() const { return n; }
double Core::grade() const
{
return ::grade(midterm, final, homework);
}
istream& Core::read_common(istream& in)
{
// read and store the student's name and exam grades
in >> n >> midterm >> final;
return in;
}
istream& Core::read(istream& in)
{
read_common(in);
read_hw(in, homework);
return in;
}
istream& Grad::read(istream& in)
{
read_common(in);
in >> thesis;
read_hw(in, homework);
return in;
}
double Grad::grade() const
{
return min(Core::grade(), thesis);
}
bool compare(const Core& c1, const Core& c2)
{
return c1.name() < c2.name();
}
bool compare_Core_ptrs(const Core* cp1, const Core* cp2)
{
return compare(*cp1, *cp2);
}
#ifndef GUARD_Student_info
#define GUARD_Student_info
#include <iostream>
#include <string>
#include "Core.h"
#include "Handle.h"
class Student_info {
public:
Student_info() { }
Student_info(std::istream& is) { read(is); }
// no copy, assign, or destructor: they're no longer needed
std::istream& read(std::istream&);
std::string name() const {
if (cp) return cp->name();
else throw std::runtime_error("uninitialized Student");
}
double grade() const {
if (cp) return cp->grade();
else throw std::runtime_error("uninitialized Student");
}
static bool compare(const Student_info& s1,
const Student_info& s2) {
return s1.name() < s2.name();
}
private:
Handle<Core> cp;
};
#endif
#include <iostream>
#include "Student_info.h"
#include "Core.h"
using std::istream;
istream& Student_info::read(istream& is)
{
char ch;
is >> ch; // get record type
// allocate new object of the appropriate type
// use `Handle<T>(T*)' to build a `Handle<Core>' from the pointer to that object
// call `Handle<T>::operator=' to assign the `Handle<Core>' to the left-hand side
if (ch == 'U')
cp = new Core(is);
else
cp = new Grad(is);
return is;
}
#ifndef GUARD_Student_info_h
#define GUARD_Student_info_h
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include "Core.h"
class Student_info {
public:
// constructors and copy control
Student_info(): cp(0) { }
Student_info(std::istream& is): cp(0) { read(is); }
Student_info(const Student_info&);
Student_info& operator=(const Student_info&);
~Student_info() { delete cp; }
// operations
std::istream& read(std::istream&);
std::string name() const {
if (cp) return cp->name();
else throw std::runtime_error("uninitialized Student");
}
double grade() const {
if (cp) return cp->grade();
else throw std::runtime_error("uninitialized Student");
}
static bool compare(const Student_info& s1,
const Student_info& s2) {
return s1.name() < s2.name();
}
private:
Core* cp;
};
#endif
#include <iostream>
#include "Core.h"
#include "Student_info.h"
using std::istream;
istream& Student_info::read(istream& is)
{
delete cp; // delete previous object, if any
char ch;
is >> ch; // get record type
if (ch == 'U') {
cp = new Core(is);
} else {
cp = new Grad(is);
}
return is;
}
Student_info::Student_info(const Student_info& s): cp(0)
{
if (s.cp) cp = s.cp->clone();
}
Student_info& Student_info::operator=(const Student_info& s)
{
if (&s != this) {
delete cp;
if (s.cp)
cp = s.cp->clone();
else
cp = 0;
}
return *this;
}
#include <algorithm>
#include <ios>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <vector>
#include "Handle.h"
#include "Student_info.h"
using std::cin;
using std::cout;
using std::domain_error;
using std::endl;
using std::sort;
using std::streamsize;
using std::setprecision;
using std::setw;
using std::string;
using std::vector;
using std::max;
bool compare_Core_handles(const Handle<Core>& lhs, const Handle<Core>& rhs) {
return compare(*lhs, *rhs);
}
int main()
{
vector< Handle<Core> > students; // changed type
Handle<Core> record; // changed type
char ch;
string::size_type maxlen = 0;
// read and store the data
while (cin >> ch) {
if (ch == 'U')
record = new Core; // allocate a `Core' object
else
record = new Grad; // allocate a `Grad' object
record->read(cin); // `Handle<T>::->', then `virtual' call to `read'
maxlen = max(maxlen, record->name().size()); // `Handle<T>::->'
students.push_back(record);
}
// `compare' must be rewritten to work on `const Handle<Core>&'
sort(students.begin(), students.end(), compare_Core_handles);
// write the names and grades
for (vector< Handle<Core> >::size_type i = 0;
i != students.size(); ++i) {
// `students[i]' is a `Handle', which we dereference to call the functions
cout << students[i]->name()
<< string(maxlen + 1 - students[i]->name().size(), ' ');
try {
double final_grade = students[i]->grade();
streamsize prec = cout.precision();
cout << setprecision(3) << final_grade
<< setprecision(prec) << endl;
} catch (domain_error e) {
cout << e.what() << endl;
}
// no `delete' statement
}
return 0;
}
#include <algorithm>
#include <iomanip>
#include <ios>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include "Student_info.h"
using std::cin;
using std::cout;
using std::domain_error;
using std::endl;
using std::setprecision;
using std::setw;
using std::sort;
using std::streamsize;
using std::string;
using std::vector;
using std::max;
int main()
{
vector<Student_info> students;
Student_info record;
string::size_type maxlen = 0;
// read and store the data
while (record.read(cin)) {
maxlen = max(maxlen, record.name().size());
students.push_back(record);
}
// alphabetize the student records
sort(students.begin(), students.end(), Student_info::compare);
// write the names and grades
for (vector<Student_info>::size_type i = 0;
i != students.size(); ++i) {
cout << students[i].name()
<< string(maxlen + 1 - students[i].name().size(), ' ');
try {
double final_grade = students[i].grade();
streamsize prec = cout.precision();
cout << setprecision(3) << final_grade
<< setprecision(prec) << endl;
} catch (domain_error e) {
cout << e.what() << endl;
}
}
return 0;
}
#include <vector>
#include <string>
#include <algorithm>
#include <iomanip>
#include <ios>
#include <iostream>
#include <stdexcept>
#include "Core.h"
using std::cout;
using std::cin;
using std::domain_error;
using std::endl;
using std::setprecision;
using std::setw;
using std::streamsize;
using std::sort;
using std::string;
using std::vector;
using std::max;
int main()
{
vector<Core*> students; // store pointers, not objects
Core* record; // temporary must be a pointer as well
char ch;
string::size_type maxlen = 0;
// read and store the data
while (cin >> ch) {
if (ch == 'U')
record = new Core; // allocate a `Core' object
else
record = new Grad; // allocate a `Grad' object
record->read(cin); // `virtual' call
maxlen = max(maxlen, record->name().size());// dereference
students.push_back(record);
}
// pass the version of `compare' that works on pointers
sort(students.begin(), students.end(), compare_Core_ptrs);
// write the names and grades
for (vector<Core*>::size_type i = 0;
i != students.size(); ++i) {
// `students[i]' is a pointer that we dereference to call the functions
cout << students[i]->name()
<< string(maxlen + 1 - students[i]->name().size(), ' ');
try {
double final_grade = students[i]->grade();
streamsize prec = cout.precision();
cout << setprecision(3) << final_grade
<< setprecision(prec) << endl;
} catch (domain_error e) {
cout << e.what() << endl;
}
delete students[i]; // free the object allocated when reading
}
return 0;
}
#ifndef GUARD_Student_info
#define GUARD_Student_info
#include <string>
#include <vector>
class Student_info {
public:
Student_info(); // construct an empty `Student_info' object
Student_info(std::istream&); // construct one by reading a stream
std::string name() const { return n; }
bool valid() const { return !homework.empty(); }
std::istream& read(std::istream&);
double grade() const;
private:
std::string n;
double midterm, final;
std::vector<double> homework;
};
bool compare(const Student_info&, const Student_info&);
#endif
#include <iostream>
#include <vector>
#include "grade.h"
#include "Student_info.h"
using std::istream;
using std::vector;
double Student_info::grade() const
{
return ::grade(midterm, final, homework);
}
bool compare(const Student_info& x, const Student_info& y)
{
return x.name() < y.name();
}
Student_info::Student_info(): midterm(0), final(0) { }
Student_info::Student_info(istream& is) { read(is); }
// read homework grades from an input stream into a `vector<double>'
istream& read_hw(istream& in, vector<double>& hw)
{
if (in) {
// get rid of previous contents
hw.clear();
// read homework grades
double x;
while (in >> x)
hw.push_back(x);
// clear the stream so that input will work for the next student
in.clear();
}
return in;
}
istream& Student_info::read(istream& in)
{
in >> n >> midterm >> final;
read_hw(in, homework);
return in;
}
#include <algorithm>
#include <iomanip>
#include <ios>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
using std::max;
#include "Student_info.h"
#include "median.h"
using std::cin; using std::cout;
using std::domain_error; using std::endl;
using std::setprecision; using std::setw;
using std::sort; using std::streamsize;
using std::string; using std::vector;
int main()
{
vector<Student_info> students;
Student_info record;
string::size_type maxlen = 0;
// read and store the data
while (record.read(cin)) {
maxlen = max(maxlen, record.name().size());
students.push_back(record);
}
// alphabetize the student records
sort(students.begin(), students.end(), compare);
for (vector<Student_info>::size_type i = 0;
i != students.size(); ++i) {
cout << students[i].name()
<< string(maxlen + 1 - students[i].name().size(), ' ');
try {
double final_grade = students[i].grade();
streamsize prec = cout.precision();
cout << setprecision(3) << final_grade
<< setprecision(prec) << endl;
} catch (domain_error e) {
cout << e.what() << endl;
}
}
return 0;
}
#ifndef GUARD_Student_info
#define GUARD_Student_info
class Student_info {
public:
Student_info();
Student_info(std::istream&);
std::string name() const { return n; }
bool valid() const { return !homework.empty(); }
std::istream& read(std::istream&);
double grade() const;
private:
std::string n;
double midterm, final;
std::vector<double> homework;
};
bool compare(const Student_info&, const Student_info&);
#endif
double Student_info::grade() const
{
return ::grade(midterm, final, homework);
}
bool compare(const Student_info& x, const Student_info& y)
{
return x.name() < y.name();
}
Student_info::Student_info(): midterm(0), final(0) { }
Student_info::Student_info(std::istream& is) { read(is); }
#include <string>
std::istream& Student_info::read(std::istream& in)
{
in >> n >> midterm >> final;
::read_hw(in, homework);
return in;
}
int main(int argc, char* argv[])
{
using namespace std;
Student_info record;
string::size_type maxlen = 0;
// read and store the data
while (record.read(cin)) {
maxlen = max(maxlen, record.name().size());
...
}
...
return 0;
}
참조 사이트: