C大学教程C++部分 chapter20 ~ chapter 22摘录,总结,及相关代码

20.2.Time Class Case Study
- point 1 the preprocessor wrapper
1.the code

#ifdef TIME_H  
#define TIME_H  
.......    
#endif  

2.the function
(1)prevent the code in the header file being included into the same source code more than once,
(2)since a class can be defined only once , using such preprocessor directives prevents multiple-definition errors.

  • point 2 the data member and member function
    1.the data members of a class cannot be initialized where they are declared in the class body. it is strongly recommended that these data members be initialized by the class’s constructor.(as there is no default initialization for fundamental-type data members)

  • point 3 parameterized stream manipulator setfill and the setw
    1.the setfill()
    (1)the function:to specify the fill character that is displayed when an integer is output in a field wider than the number of digits in the value.
    (2)by default .the fill character appear to the left of the digits in the number.
    (3)once the fill character is specified with setfill,it applies for all subsequent values that are displayed in fields wider than the value being displayed (setfill is a sticky setting)
    (4)setw,aplies only to the next value displayed (nonsticky language)

  • point 3 Class Scope
    1.even though a member function declared in a class definition may be defined outside that class (and tied to the class via the ‘::’ ),that member function is still within the class’s scope .
    2.its name is only known to other members of the class unless refered to via an object of the class, a reference to an object of the class , a pointer to an object of the class or the binary scope resolution operator
    4.if a member function is defined in the body of a class definition,the C++ compilier attempts to inline calls to the member function
    5.only the simplest and most stable member functions should be defined in the class definition

20.3 Class Scope and Accessing Class Members
the code

#include< iostream>
    using namespace std ;

    class Count{
    public: 
    void setX( int value ){
           x = value ;
    }

    void print(){
           cout<<x<<endl ;
    }

    private: 
    int x;
    };

    int main(){
    Count counter;
    Count *counterPtr =&counter ;
    Count &counterRef = counter ;

    cout<<"set x to 1 and print using the object's name: "<<endl;
    counter.setX(1);
    counter.print();

    cout<<"set x to 2 and print using a reference to an object: "<<endl;
    counterRef.setX(2);
    counterRef.print();

    cout<<"set x to 3 and print using a pointer to an object: "<<endl;
    counterPtr->setX(3);
    counterPtr->print();

    return 0;
    }  
  • a class’s data member and member functions (functions declared in the class definition) belong to the class’s scope, Nonmember functions are defined at file scope.
  • within a class’s scope , class members are immediately accessible by all of that class’s member functions and can be refered by name,
  • outside a class’s scope , public class members are referenced through one of the handles on an object-an object name, a reference to an object or pointer to an object
  • member functions can be overloaded, but only by other member functions of that class.to overload a member function, simply provide in the class definition a prototype for each version of the overloaded function, and provide a separate function definition for each version of the function
  • variable declared in a member function have block scope and are known only to that function.
  • variables declared in a member function have block scope and are known only to that function,
  • if a member function defines a variable with the same name as a variable with class scope.the class-scope variable is hidden by the block-scope variable in the block scope.such the hidden variable can be accessed by use the format
    class::variablename

    to access them.
  • the . and the ->

20.4 separating interface from implementation
20.5 access function and utility functions
- access functions can read or dsplay data,another common use for access functions is to test the truth or falsity of condition-such functions are often called predicate functions , an example would be an isEmpty function for any container class - a class capable of holding many objects - such as the linked list , a stack or a queue. a program might test isEmpty before attempting to read another item from the container object , another example is the isFull function .
- utility function ( also called the help function) , an utility function is not part of the class’s public interface , rather , it is private member function that supports the operation of the class’s public member functions, unity functions are not intended to be used by clients of a class (but can be used by **friend**s of a class )

20.6 constructors with default argument

Time(int = 0 , int = 0 , int = 0);  

20.7 Destructors
- a destructor is another type of special member function.
- the name of it if ‘~’ followed by the class name.
- a class’s desstructor is called implicitly when an object is destroyed .
- the destructor itself does not actually release the object’s memory-it performs termination housekeeping before the system recliams the object’s memory. so the memory may be reused to hold new object.
- a destructor receives no parameters and return no value.
- a destructor may not specify a return type. not even void.
- destructor overloading is not allowed.

~~~ c++
#pragma once
//CreateAndDestroy.h
#ifndef CREAT_H
#define CREAT_H
#include<string>
using namespace std;

class CreateAndDestroy {

public: 
    CreateAndDestroy(int, string);  // constructor
    ~CreateAndDestroy();            //destructor

private:
    int objectID;                   //ID number for object
    string message;                 //message describing object

};
#endif

//CreateAndDestroy,cpp
#include<iostream>
#include"CreateAndDestroy.h"
using namespace std;

//constructor
CreateAndDestroy::CreateAndDestroy( int ID , string messageString ) {
    objectID= ID;
    message = messageString;
    cout << "object " << objectID << " constructr runs "
        << message << endl;

}

CreateAndDestroy::~CreateAndDestroy() {
    cout << (objectID == 1 || objectID == 6 ? "\n" : "");

    cout << "object " << objectID << " destructor runs "
        << message << endl;
}



//main.cpp
#include<iostream>
#include"CreateAndDestroy.h"
using namespace std;

void create(void) {
    cout << "\nCREATE FUNCTION: EXECUTION BEGINS" << endl;
    CreateAndDestroy fifth(5, "(local automatic in create)");
    static CreateAndDestroy sixth(6, "(local static in create)");
    CreateAndDestroy seventh(7, "(local automatic in create)");
    cout << "\nCREATE FUNCTION: EXECUTION ENDS" << endl;
}
CreateAndDestroy first(1, "(global before main)");
int main() {
    cout << "\nMAIN FUNCTION: EXECUTION BEGINS " << endl;
    CreateAndDestroy second(2, "(local automatic in main)");
    static CreateAndDestroy third(3, "(local static in main)");

    create();
    CreateAndDestroy fourth(4, "(local automatic in main)");
    cout << "\nMAIN FUNCTION: EXECUTION ENDS" << endl;

    return 0;

}

����
����дͼƬ����

20.8 when constructors and destructors are called
- constructors and destructors are called implicitly by the compiler. the order in which these function calls occur depends on the order in which execution enters and leaves the scope where the onjects are instantiated .
- generally, destructor calls are made in the reverse order of the correspondin constructor calls, but as we
have seen , the storage classes of objects can alter the order in which destructors are called .
- terminate

1.return 0;

2.exit:force a program to terminate immediately and does not execute the destructors of automatic objects.the function is often used to terminate a program when an error is detected in the input or if a file to be processed by the program cannot be opened.

3.abort:force the program to terminate immediately, without allowinng the destructors of any objects to be called , function is usually used to indicate an abnormal termination of the program

20.9 Time class case study: a subtle Trap-returning s reference to a private data member.

~~~c++  
#pragma once
//Time.h
#ifndef TIME_H
#define TIME_H

class Time {
public:
    Time(int = 0, int = 0, int = 0);
    void setTime(int, int, int);
    int getHour();
    int &badSetHour(int);
private:
    int hour;
    int minute;
    int second;

};
#endif


//Time.cpp
#include"Time.h"
Time::Time(int hour, int minute, int second) {
    setTime(hour, minute, second);
}
void Time::setTime(int h, int m, int s) {
    hour = (h >= 0 && h < 24) ? h : 0;
    second = (s >= 0 && s < 60) ? s : 0;
    minute = (m >= 0 && m < 60) ? m : 0;

}

int Time::getHour() {
    return hour;
}
int  & Time::badSetHour(int h) {
    hour = (h >= 0 && h < 24) ? h : 0;
    return hour;
    //dangerous reference return
}


//main.cpp
#include<iostream>
#include"Time.h"
using namespace std;

int main() {
    Time t;
    //initialize hourRef with the rreference returned by the badsetHour
    int &hourRef = t.badSetHour(20);

    cout << "valid hour before modifacation: " << hourRef;
    hourRef = 30;
    cout << "\ninvalid hour before mdifation: " << t.getHour();

    //dangerous fuction call that returning
    //a reference can be used as an lvalue
    t.badSetHour(12) = 24;

    cout << "\n\n********************************************\n"
        << "POOR PROGRAMMING PRACTICE!!!!!!!!\n"
        << "t.badSetHour(12) as an lvalue, invalid hour: "
        << "\n**********************************************\n" << endl;

    return 0;

}


20.10 dedfault memberwise assignment

#pragma once
//Date.h
#ifndef DATE_H
#define DATE_H

class Date {
public:
    Date(int = 1, int = 1, int = 2000);
    //constructor

    void print();
private:
    int month;
    int day;
    int year;

};
#endif


//Date.cpp
#include<iostream>
#include"Date.h"
using namespace std;

Date::Date(int m, int d, int y) {
    month = m;
    day = d;
    year = y;
}

void Date::print() {
    cout << month << '/' << day << '/' << year << endl;
}

//test.cpp
#include<iostream>
using namespace std;
#include"Date.h"

int main() {
    Date date1(7, 4, 2004);
    Date date2;

    cout << "dete1 = ";
    date1.print();
    cout << "\ndate2 = ";
    date2.print();

    date2 = date1;
    cout << "\n\n after default memberwise assignment , date2 = ";
    date2.print();
    cout << endl;

    return 0;

}
  • the assignment operator (=) can be used to assign an object to another object of the same type.
  • by default , such assignment is performed by mambberwise assignment-each data member of the object on the right of the assignment operator is assigned to the same data member in the object on the left of the assignment operator.
  • objects may be passed as function arguements and may be returned from the functions .such passng and returning is performed using pass-by-value by default - a copy of the object is passed or returned .
  • for each class , the compiler provides a default coppy constructor to copy te original object’s values into the new object.but it can cause serious problems when used with a class whose data members contain pointers to dynamically allocated memory.

chapter 21

21.2 const (constant) objects and const Member function

  • some objects need to be modifiable and some do not , the programmer may use keyword const to specify that an object is not modificable and that any attempt to modify the object should result in a compilation error.the statement
    ~c++
    const Time noon (12,0,0);
    ~
  • c++ compilers disallow member-function calls for const objects unless the member functions themselves are also declared const , this is true even for get functions that do not modify the object, in addition , the compiler does not allow member functions declared const to modify the object.
//Time.h
#pragma once
#ifndef TIME_H
#define TIME_H

class Time
{
public:
    Time(int = 0, int = 0, int = 0);
    //constructor

    //set function
    void setTime(int, int, int);
    void setHour(int);
    void setMinute(int);
    void setSecond(int);

    //get function (usually declared const)
    int getHour() const;
    int getMinute() const;
    int getSecond() const;

    //printFuunction(normally declared const)
    void printInUniversal() const;
    void printInStandard() const;

private:
    int hour;
    int minute;
    int second;


};

#endif

//Time.cpp
#include<iostream>
#include<iomanip>
using namespace std;

#include"Time.h"

Time::Time(int hour, int minute, int second) {
    setTime(hour, minute, second);
}

void Time::setTime(int hour, int minute, int second) {
    setHour(hour);
    setMinute(minute);
    setSecond(second);
}

void Time::setHour(int h) {
    hour = (h >= 0 && h < 60) ? h : 0;

}

void Time::setMinute(int m) {
    minute = (m >= 0 && m < 60) ? m : 0;

}

void Time::setSecond(int s) {
    second = (s >= 0 && s < 60) ? s : 0;

}

int Time::getHour() const {
    return hour;
}

int Time::getMinute() const {
    return minute;
}

int Time::getSecond() const {
    return second;
}

void Time::printInStandard() const {

    cout << setfill('0') << setw(2) << (hour % 12) << ":"
        << setw(2) << minute << ":" << setw(2)
        << second;

    if (hour < 12) cout << "AM" << endl;
    else cout << "PM" << endl;
}

void Time::printInUniversal() const{
    cout << setfill('0') << setw(2) << hour << ":"
        << setw(2) << minute << ":" << setw(2)
        << second << endl;
}

//main.cpp
#include<iostream>
#include"Time.h"
using namespace std;

int main() {
     Time noon(12, 0, 0);

    noon.getHour();
    noon.setTime(12, 2, 34);
    noon.getSecond();
    noon.printInStandard();
    noon.printInUniversal();
}
//Increment.h
#pragma once
#ifndef INCREMENT_H
#define INCREMENT_H

class Increment {
public:
    Increment(int c = 0, int i = 1);
    //constructor

    void addIncrement() {
        count += increment;
    }

    void print() const;
private:
    int count;
    const int increment;
};
#endif
//Increment.cpp
#include<iostream>
using namespace std;
#include"Increment.h"
Increment::Increment(int c, int i) 
    :count(c),
     increment(i)
{  

}

void Increment::print() const {
    cout << "count = " << count << ", increment =  " << increment << endl;
}


//test.cpp
#include<iostream>
#include"Increment.h"
using namespace std;

int main() {
    Increment value(10, 5);
    cout << "before increment: " << endl;
    value.print();

    for (int index = 1; index <= 4; index++) {
        value.addIncrement();
        cout << "after increment " << index << ":"<<endl;
        value.print();

    }
}
//Increment.h
#pragma once
#ifndef INCREMENT_H
#define INCREMENT_H

class Increment {
public:
    Increment(int c = 0, int i = 1);
    //constructor

    void addIncrement() {
        count += increment;
    }

    void print() const;
private:
    int count;
    const int increment;
};
#endif
//Increment.cpp
#include<iostream>
using namespace std;
#include"Increment.h"
Increment::Increment(int c, int i) 

{  
        count = c;
        increment = i;
}

void Increment::print() const {
    cout << "count = " << count << ", increment =  " << increment << endl;
}

//test.cpp
#include<iostream>
#include"Increment.h"
using namespace std;

int main() {
    Increment value(10, 5);
    cout << "before increment: " << endl;
    value.print();

    for (int index = 1; index <= 4; index++) {
        value.addIncrement();
        cout << "after increment " << index << ":"<<endl;
        value.print();

    }
}
  • an interesting problem arises , for constructors and destructors,each of which typically modifies objects , the const declaration is not allowed for constructions and destructors , an constructor must be able to modify an object so that the object can be initialized properly, a destructor must be able to perform its termination housekeeping chores before an object’s memory is reclaimed by the system.
  • note that constructor can still be used to initialize a const object. invoking a non-const function from the constructor call as part of the initialization of a const object is allowed.
initialzing a const Data member with a member initialzer.
  • using member initializer syntax.

- all data members can be initialized using member initializer syntax,but const data members and data members that are references must be initialized using member initiaizers.

Increment::Increment(int c, int i) 
    :count(c),
     increment(i)
{  

}

21.3:composition:objects as members of classes

  • how an object’s constructr can pass argument to member
    object constructor.
  • code
#pragma once
//Date.h
#ifndef DATE_H
#define DATE_H

class Date {
public:
    //default constructor
    Date(int = 1, int = 1, int = 1);

    //print data in month/day/year format
    void print() const;

    //destructor
    ~Date();
private:
    int month;
    int day;
    int year;

    //utility function to check if day is proper for month and year
    bool checkDay(int ) const;
};
#endif
//Date.cpp
#include<iostream>
#include<iomanip>
using namespace std;

#include"Date.h"

Date::Date(int mon, int day, int yea) {
    if (mon <= 12 && mon > 0)
        this->month = mon;
    else {
        cout << "invalid input we will set the month to 1 !" << endl;
        this->month = 1;
    }

    this->year = yea;

    if (this->checkDay(day)) {
        this->day = day;
    }
    else {
        cout << "invalid input we will set the day to 1 !" << endl;
        this->day = 1;
    }


}

void Date::print() const {
    cout << setfill('0') << setw(2) << this->month << '/' << setw(2) << this->day << '/' << setw(4) << this->year << endl;
}

bool Date::checkDay(int day) const {
    //int num;
    //cin >> num;
    int array1[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    int array2[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

    bool flag = ((this->year % 4 == 0 && this->year % 100 != 0) || this->year % 400 == 0);

    //cin >> num;

    if (flag) {
        //cout << 1<<endl;
        //cin >> num;
        if (day <= array2[this->month - 1] && day > 0)
            return true;
        else
            return false;
    }
    else {
        //cout << 2 << endl;
        //cin >> num;
        if (day <= array1[this->month - 1] && day > 0) {
            //cout << 2.1 << endl;
            return true;
        }
        else {
            //cout << 2.2 << endl;
            return false;
        }
    }

}

Date::~Date() {
    cout << "destructor for date runs !" << endl;
}

#pragma once
//Employee.h
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
#include"Employee.h"
#include"Date.h"

class Employee {
public:
    //constructor
    Employee(const char* const, const char* const, const Date &, const Date&);

    //print in a special format string string hired: / /  Birthday: / / 
    void print() const;

    //destructor
    ~Employee();

private:
    char firstName[25];
    char lastName[25];
    const Date birthDate;
    const Date hireDate;
};

#endif

//Employee.cpp
#include<iostream>
#include<cstring>
#include<string.h>
using namespace std;

#include"Employee.h"
#include"Date.h"

Employee::Employee(const char* const first, const char* const last, const Date & dateOfBirth, const Date& dateOfHire)
    :birthDate(dateOfBirth),
    hireDate(dateOfHire) 
{
    int length = strlen(first);
    length = (length < 25) ? length : 24;
    strncpy_s(this->firstName,25, first, length);
    firstName[length] = '\0';

    length = strlen(last);
    length = (length < 25) ? length : 24;
    strncpy_s(this->lastName,25, last, length);
    firstName[length] = '\0';

    cout << "Employee object runs: " << this->firstName << " " << this->lastName << endl;

}

void Employee::print() const {
    cout << this->firstName << " " << this->lastName << endl;
    this->birthDate.print();
    this->hireDate.print();

    cout << endl;

}

Employee::~Employee() {
    cout << "destructor object runs: " << this->firstName << " " << this->lastName << endl;
}


//test.cpp
#include<iostream>
using namespace std;

#include"Employee.h"
#include"Date.h"

int main() {
    Date birth(7, 24, 1949);
    Date hire(3, 12, 1988);

    Employee manager("Bob", "Blue", birth, hire);

    cout << endl;
    manager.print();

    cout << "test invalid input " << endl;
    Date fire(14,35,1994);
    fire.print();

}

注意:strncpy_s的用法。

21.4 friend function and friend class.
  • code:
#include<iostream>
using namespace std;
class Count {
    friend void setX(Count &, int);
public:
    Count()
        :x(0)   //initial 0
    {

    }
    void print() const {
        cout << x << endl;
    }
private:
    int x;

};

void setX(Count&c, int val) {
    c.x = val;
   c.print();
   cout<<endl;
}

int main() {
    Count counter;

    cout << "counter.x after instantiation: ";
    counter.print();

    setX(counter, 8);
    cout << "counter.x after call to setX function: ";
    counter.print();

    return 0;
}
  • description:
    a member function of a class is defined outside that class’s scope,yet have the right to access the public and non-public members of the class.stand-alone functions or the whole class may be declared to be a friend of another class.
  • later,friend functions are used to overload operators for use with the class object.
friend class classTwo;
  • friendship is granted , not taken,is neither symmeritic or transtive.
    A friend of B, B friend of C
    B may be not the friend of A,A may be not the friend of C
//电视机与遥控器
#include <iostream>
using namespace std;
class TV
{
public:
    friend class Tele;
    TV() :on_off(off), volume(20), channel(3), mode(tv) {}
private:
    enum { on, off };
    enum { tv, av };
    enum { minve, maxve = 100 };
    enum { mincl, maxcl = 60 };
    bool on_off;
    int  volume;
    int channel;
    int mode;
};
class Tele
{
public:
    void OnOFF(TV&t) { t.on_off = (t.on_off == t.on) ? t.off : t.on; }
    void SetMode(TV&t) { t.mode = (t.mode == t.tv) ? t.av : t.tv; }
    bool VolumeUp(TV&t);
    bool VolumeDown(TV&t);
    bool ChannelUp(TV&t);
    bool ChannelDown(TV&t);
    void show(TV&t)const;
};
bool Tele::VolumeUp(TV&t)
{
    if (t.volume<t.maxve)
    {
        t.volume++;
        return true;
    }
    else
    {
        return false;
    }
}
bool Tele::VolumeDown(TV&t)
{
    if (t.volume>t.minve)
    {
        t.volume--;
        return true;
    }
    else
    {
        return false;
    }
}
bool Tele::ChannelUp(TV&t)
{
    if (t.channel<t.maxcl)
    {
        t.channel++;
        return true;
    }
    else
    {
        return false;
    }
}
bool Tele::ChannelDown(TV&t)
{
    if (t.channel>t.mincl)
    {
        t.channel--;
        return true;
    }
    else
    {
        return false;
    }
}
void Tele::show(TV&t)const
{
    if (t.on_off == t.on)
    {
        cout << "电视现在" << (t.on_off == t.on ? "开启" : "关闭") << endl;
        cout << "音量大小为:" << t.volume << endl;
        cout << "信号接收模式为:" << (t.mode == t.av ? "AV" : "TV") << endl;
        cout << "频道为:" << t.channel << endl;

    }
    else
    {
        cout << "电视现在" << (t.on_off == t.on ? "开启" : "关闭") << endl;
    }

}
int main()
{
    Tele t1;
    TV t2;
    t1.show(t2);
    t1.OnOFF(t2);
    t1.show(t2);
    cout << "调大声音" << endl;
    t1.VolumeUp(t2);
    cout << "频道+1" << endl;
    t1.ChannelUp(t2);
    cout << "转换模式" << endl;
    t1.SetMode(t2);
    t1.show(t2);
    return 0;
}
21.5 using the this Pointer
  • we have seen an object’s member functions can manipulate the object’s data,how do member functions know which obbject’s data members to manipulate? every object has access to own address through pointer called this.
  • an object’s this pointer is not part of the object itself - i.e the size of the memory occupied by the this pointer is not reflected in the result of a sizeof operator on the object.rather , it is passed (by the compiler) as an implict argument to each of the object’s non-static member functions.
  • object use the this pointer implicitly or explicitly to reference their data members and member functions, the type of the this pointer depends on the type of the member function in which this pointer is used is declared const.
  • non- constant member function:type *const.
  • constant member function: const type* const
using the this pointer to enable Cascaded Function Calls.
  • another use of the this pointer is to enable cascaded member-function calls in whichmultiple functions are invoked in the same statement.
#pragma once
#ifndef TIME_H
#define TIME_H

class Time
{
public:
    Time(int = 0, int = 0, int = 0);
    //constructor

    //set function
    Time& setTime(int, int, int);
    Time& setHour(int);
    Time& setMinute(int);
    Time& setSecond(int);

    //get function (usually declared const)
    int getHour() const;
    int getMinute() const;
    int getSecond() const;

    //printFuunction(normally declared const)
    void printInUniversal() const;
    void printInStandard() const;

private:
    int hour;
    int minute;
    int second;


};

#endif

#include<iostream>
#include<iomanip>
using namespace std;

#include"Time.h"

Time::Time(int hour, int minute, int second) {
    setTime(hour, minute, second);
}

Time& Time::setTime(int hour, int minute, int second) {
    setHour(hour);
    setMinute(minute);
    setSecond(second);
    return *this;
}

Time& Time::setHour(int h) {
    hour = (h >= 0 && h < 60) ? h : 0;
    return *this;
}

Time& Time::setMinute(int m) {
    minute = (m >= 0 && m < 60) ? m : 0;
    return *this;
}

Time& Time::setSecond(int s) {
    second = (s >= 0 && s < 60) ? s : 0;
    return *this;
}

int Time::getHour() const {
    return hour;
}

int Time::getMinute() const {
    return minute;
}

int Time::getSecond() const {
    return second;
}

void Time::printInStandard() const {

    cout << setfill('0') << setw(2) << (hour % 12) << ":"
        << setw(2) << minute << ":" << setw(2)
        << second;

    if (hour < 12) cout << "AM" << endl;
    else cout << "PM" << endl;
}

void Time::printInUniversal() const{
    cout << setfill('0') << setw(2) << hour << ":"
        << setw(2) << minute << ":" << setw(2)
        << second << endl;
}



#include<iostream>
#include"Time.h"
using namespace std;

int main() {
    Time noon;
    noon.setHour(12).setMinute(0).setSecond(0);

    noon.getHour();
    /*
    noon.setTime(12, 2, 34);
    */
    noon.getSecond();
    noon.printInStandard();
    noon.printInUniversal();
}
21.6 Dynamic Memory Management with operator new and delete.
  • c++ enables Programmers to control the allocation and deallocation of memory in a program for any built-in or user-defined type. this is known as dynamic memory management and is performed with ooperators new and delete.
Time *timePtr;
timePtr = new Time;
delete timePtr;
double *ptr = new double(3.1415926);
Time *timePtr = new Time(12,45,0);
int *array = new int[10];
delete[] array;
21.7 static class members
  • there is an important exception to the rule of a class has its own copy of all the data members of the class.in certain case, only one copy of a variable shouldbe shared by all objects of a class. a static data member is used for these and other reasons. such a variable represents “classwide” information (i.e a property of the class shared by all instances, not a properity of a specific object of the class.) the declaration of static member begins with the keyword ststic.
  • although they may seen like global variables , a clss’s static data members have class scope , also , static members can be declared public,private,or protected , a fundamental-type static data member is initialed by default 0, if you want a different initial value, a static data member can be initialed once(and only once) a const static data member of int or enum type can be initialed in its declaration in the class definition.
  • a class’s private or protected static members are normallly accessed through public member functions of the class or through friends of the class.(later we will see class’s private or protected ststic members can also be accessed through protected member functions of the class).
  • a static members can exist even no objects of that class exist.this time,to access it use the format(TYPE::DATAMEMBER) ,like
Date::number.  
#pragma once
//Employee.h
#ifndef EMPLOY_H
#define EMPLOY_H

class Employee
{
public:
    Employee(const char * const, const char * const);
    ~Employee();
    const char *getFirstName() const;
    const char *getLastName() const;
    static int getCount();
private:
    char *firstName;
    char *lastName;

    static int count;
};
#endif

//Employee.cpp
#include<iostream>
#include<string>
using namespace std;
#include"Employee.h"

int Employee::count = 0;

int Employee::getCount()
{
    return count;
}

Employee::Employee(const char*const  first, const char* const last) {
    firstName = new char[strlen(first) + 1];
    strcpy(firstName, first);
    lastName = new char[strlen(last) + 1];
    strcpy(lastName, last);

    count++;

    cout << "Employee constructor for " << firstName << " " << lastName << endl;
}

Employee::~Employee() {
    cout << "~Employee() called for " << firstName << " " << lastName << endl;
    delete[] firstName;
    delete[] lastName;

    count--;
}

const char * Employee::getFirstName() const {
    //const before return type prevents client from modifying
    //private data;client should copy returned before 
    //destructive delete storage to prevent undifined pointer
    return firstName;
}

//main.cpp
#include<iostream>
using namespace std;
#include"Employee.h"

int main() {
    //use class name and binary scope resolution operator to
    //access static number function getCount
    cout << "number of employee before instantiation of any object is "
        << Employee::getCount() << endl;

    //use new to dynamically create two new Employees
    //operator new also call the object's constructor
    Employee *e1Ptr = new Employee("susan", "Baker");
    Employee *e2Ptr = new Employee("Robert", "Jones");

    //call getCount on first Employee bject
    cout << "number of Employees after objects are instantiated is "
        << e1Ptr->getCount() << endl;

    delete e1Ptr;
    e1Ptr = NULL;
    delete e2Ptr;
    e2Ptr = NULL;

    cout << "number of employee after deletion is "
        << Employee::getCount() << endl;
}
  • note: a member function should be declared static if it doesn’t access non-static member functions or non-static member functions of the class , unlike non-static member functions , a static member function does not have a this pointer , because static data members and static member functions exist independently of any objects of a class,the this pointer must refer to a specific object of the class, and when a static member function is called , their might not be any objects of its class in memory.
21.8 Data Abstraction and Information Hiding
  • consider the stack data structure.
  • stack can be implemented with arrays and with other data structures ,such as linked list.
  • a client of a stack class need not be concerned with the stack ‘s implementation.
  • the concept is refered to as data hiding.
  • abstract data type(ADT)
  • an abstract data type actually capature two notions,a data representation and operation.
21.8.1 Example Array abstract data type
21.8.2 Example Queue abstract data type
21.9
  • among the most popular types of classes are container classes (also called collection classes ),classes designed to hold collections of objects,Containersclasses commonly provide services such as insertion,deletion ,searching,sorting and testing an item to determine whether it is a member of the collection.
  • it is common to associate iterator objects - or more simply iterators- with container classes,an iterator is an object that walkthrough a collection,returning the next item(or performing some actions on the next item).
21.10 Proxy Classes (代理类)
  • code:
#pragma once
//Implementaion.h
class Implementation {
public:
    Implementation(int v) 
    :value(v)
    {

    }

    void setValue(int v) {
        value = v;
    }

    int getValue() {
        return value;
    }
private:
    int value;
};


#pragma once
//interface.h
#include"Implementation.h"
class Interface {
public:
    Interface(int);  //constructor
    void setValue(int);//same public interface as the clas Implementation has
    int getValue() const;
    ~Interface(); //destructor
private:
    Implementation *ptr;
};


//interface.cpp
#include"Implementation.h"
#include"Interface.h"

Interface::Interface(int v) 
    :ptr(new Implementation(v))   //initial ptr to point to a new implementation object
{

}

void Interface::setValue(int v) {
    ptr->setValue(v);
}

int Interface::getValue() const {
    return ptr->getValue();
}

Interface::~Interface() {
    delete ptr;
}



//test.cpp
#include<iostream>
using namespace  std;
#include"Interface.h"
#include"Interface.h"

int main() {
    Interface i(5);

    cout << "interface contains: " << i.getValue()
        << " before setValue" << endl;

    i.setValue(10);

    cout << "Interface contains: " << i.getValue()
        << " after setValue" << endl;

    return 0;
}

chapter 22 Operator Overloading

22.2 Fundamentals of Operator Overloading

  • C++ programming is a type-sensitive and type-focused process.Programmingers can use fundamental types and can define new type.
  • Programmers can use operators with user-defined types as well, although C++ does not allow new operators to be created, it does allow most existing operators to be overloaded so that , when these operators are used with objects, the operators have meanning appropriate to theae objects, this is a powerful capability.
  • an operator is overloaded by writting a non-static member functiondefinition or global function definition as you normally would.
  • operator+
  • to use an operator on class objects , the operator must be overloaded.

  • three exceptions.

    the assignnment may be used with every class to perform memberwise assignment of the data members of the class.we will soom see that such defauly memberwise assignment is dangerous for classes with pointer members;we will explicitly overload the assignment operator for such classes.
    the address operator and comma operators may also be used with objects of any class without overloading.

  • overloading is especially appropriate for mathmatical classes.

22.3 Restrictions on operator overloading

  • operators that can not be overloaded:’.’,’.*’,’::’,’?:’.
  • precedence associativity and number of operands .
    not change.
  • it is not possible to create new operators.
  • the meaning of how an operator works on objects of fundamental types cannot be changed by operator overloading .the programmer cannot , for example,change the meaning of how + add two integers , operator overloading works only with objects of user-defined type or with a mixture of an object of a user-defined type and an object of a fundamental type.
  • if we have overloaded the + , it doesn’t mean that we can use += without overloading it.

22.4 Operator functions as class members VS global functions

  • operator functions can be member functions or global functions,gloabl functions are often made friends for performance reasons.. member functions use the this pointer implicitly to obtain one of their class object arguments .
  • when overloading (),[],-> or any of the assignment , the operators overloading functions must be declared as a class member.
  • when an operator function is implemented as a member function , the leftmost(or only) operand must be an object (or a reference to an object) of the operator’s type,if the left operator musst be a different class or a fundamental type, this operator function must be implemented as a global function. a global operator function can be made a friends of a class if the function must access private or protected member of the class directly.
  • commutative operator: another reason why one might choose a global function to overloaded an operator is to enable the operator to be commutative.

22.5 Overloading stream insertion and stream extraction operators

#pragma once
//PhoneNumber.h
#ifndef PHONENUMBER_H
#define PHONENUMBER_H

#include<iostream>
#include<string>
using namespace std;

class PhoneNumber {
    friend ostream &operator<<(ostream &, const PhoneNumber &);
    friend istream &operator>>(istream &, PhoneNumber &);
private:
    string areaCode;         //3-digut area code
    string exchange;         //3-digit exchange
    string line;             //4-digit line
};
#endif

//PhoneNumber.cpp
#include<iomanip>
#include<iostream>
using namespace std;
#include"PhoneNumber.h"

ostream &operator<<(ostream &output, const PhoneNumber &number) {
    output << "(" << number.areaCode << ")"
        << number.exchange << "-" << number.line << endl;
    return output;

}

istream &operator>>(istream &input, PhoneNumber &number) {
    input.ignore();     //skip(
    input >> setw(3) >> number.areaCode;   //input area code
    input.ignore(2);  //skip) and space
    input >> setw(3) >> number.exchange;   //input exchange
    input.ignore();
    input >> setw(4) >> number.line;       //input line
    return input;                          //enable cin>>a>>b>>c; 
}

//test.cpp
#include<iostream>
#include"PhoneNumber.h"
using namespace std;

int main() {
    PhoneNumber phone;
    cout << "enter phone number in the form (123) 456-7890: " << endl;
    cin >> phone;

    cout << "the phone number entered was: ";
    cout << phone << endl;

    return 0;
}

overloading unary operators

  • A unary operator for a class can be overloades as a non-static member function with no arguments or as a global function with one argument.
  • example: bool operator !();

22.7 overloading binary operators

  • a binary operator can be overloaded as a non-static member function with one argument or as a global functios with two arguments.

22.8 case study: Array class

#pragma once
//Array.h
#ifndef ARRAY_H
#define ARRAY_H
#include<iostream>
using namespace std;

class Array {
    friend ostream &operator<<(ostream &, const Array &);
    friend istream &operator>>(istream &, Array &);
public:
    Array(int = 10);             //default constructor
    Array(const Array &);        //copy constructor
    ~Array();                    //destructor
    int getSize() const;         //return the size

    const Array &operator=(const Array &);     //assignment operator
    bool operator==(const Array &) const;      //equality operator

    bool operator!=(const Array &right) const {
        return !(*this == right);
    }

    int &operator[] (int);                    //subscript  operator for non-const objects return modifiable lvalue

    //subscript operator for const objects return rvalue
    int operator[] (int) const;

private:
    int size;
    int *ptr;     //pointer to first element of element of pointer-based array
};
#endif
//Array.cpp
#include<iostream>
#include<iomanip>
#include<cstdlib>
using namespace std;

#include"Array.h"

Array::Array(int ArraySize) {
    size = (ArraySize > 0) ? ArraySize : 10;
    ptr = new int[size];

    for (int index = 0; index < size; index++)
        ptr[index] = 0;
}

Array::Array(const Array&arrayToCopy) 
    :size(arrayToCopy.getSize())
{
    ptr = new int[size];

    for (int index = 0; index < size; index++)
        ptr[index] = arrayToCopy.ptr[index];
}

Array::~Array() {
    delete[] ptr;
    ptr = NULL;
}

int Array::getSize() const{
    return size;
}

const Array &Array::operator=(const Array &right) {
    if (&right != this) {
        if (size != right.getSize())
        {
            delete[] ptr;
            size = right.getSize();
            ptr = new int[size];
        }



        for (int index = 0; index < size; index++)
            ptr[index] = right.ptr[index];
    }

    return *this;
}

bool Array::operator==(const Array &right) const {
    if (size != right.size)
        return false;

    for (int index = 0; index < size; index++)
    {
        if (ptr[index] != right.ptr[index])
            return false;
    }

    return true;
}

int &Array::operator[] (int subscript)
{
    if (subscript < 0 || subscript >= size)
    {
        cout << "\nError:subscript " << subscript
            << "out of range" << endl;
        exit(1);
    }
    return ptr[subscript];
}

int Array::operator[] (int subscript) const
{
    if (subscript < 0 || subscript >= size)
    {
        cout << "\nError:subscript " << subscript
            << " out of range " << endl;
        exit(1);
    }
    return ptr[subscript];
} 

istream &operator>>(istream &input, Array &a) {
    for (int index = 0; index < a.size; index++)
        input >> a.ptr[index];
    return input;
}

ostream &operator<<(ostream &output, const Array &a) {
    int index;

    for (index = 0; index < a.size; index++)
    {
        output << setw(12) << a.ptr[index];

        if ((index + 1) % 4 == 0)
            output << endl;
    }

    if (index % 4 != 0)
        output << endl;

    return output;
}

//test.cpp
#include<iostream>
#include"Array.h"
using namespace std;

int main() {
    Array integer1(7);
    Array integer2;  //10 element Array by default

    cout << "size of Array integer1 is "
        << integer1.getSize() << "\nArray after initialization \n" << integer1;

    cout << "size of Array integer2 is "
        << integer2.getSize() << "\nArray after initialization \n" << integer2;  

    cout << "\n enter 17 entegers: " << endl;
    cin >> integer1 >> integer2;

    cout << "\n evaluating integer1 != integer2" << endl;

    if (integer1 != integer2)
        cout << "(integer1 != integer2) "<< endl;

    Array integer3(integer1);

    cout << "\nSize of Array integer3 is "
        << integer3.getSize() << "\nArray after initialition:\n" << integer3;

    cout << "assigning integer2 to integer 1 " << endl;
    integer1 = integer2;

    cout << "\nevaluating integer1 == integer2" << endl;
    if (integer1 == integer2)
        cout << "integer1 == integer2" << endl;

    cout << "\ninteger1[5] = " << integer1[5] << endl;

    cout << "\n\nassignmrnt 1000 to integer1[5]" << endl;
    integer1[5] = 1000;
    cout << "integer1" <<endl<< integer1<<endl;

    cout << "\nattempting tp assign 1000 to integer1[15]" << endl;
    integer1[15] = 1000;
    return 0;


}

22.9 Converting between types

  • most programs process information of many types , sometimes all the operation “stay within a type
  • but what about user-defined types?the compiler cannot know in advance how to convert among user-defined types, and between user-defined types and fundamental types,so the programmer must specify how to do this.such conversions can be performed with conversion constructors-single-srgument constructor that turn objects of other types(including fundamental types) into objects of a particular class.
  • a conversion operator(also called a cast operator) can be used to convert an object of a class into an object of another class or into a fundamental type.such a convertion operator must be a non-static member function , the function protype
A::operator char*() const;
  • declare an overloaded operator for converting an object of user-defined type A into a temporary char * object,the operator function is defined const because it does not modify the original object, an overloaded cast operator function does not specify a return type-the return type is the type to which the object is being converted ,if S is a class object , when the compiler sees the expression
    ~c++
    static_cast

22.10 overloading ++ and –

  • this time we will see how the compiler distinguish between prefix and postfix version of an increment or decrement.
  • to realize this , each overloaded operator function must have a distinct signature, so that the compiler will be able to determine which version of ++ is intended.
overloading the prefix increment operator
Date &operator ++(Date &);
overloading the postfix increment operator
  • the convention that has been adopted in c++ is that , when the compiler sees the postincrement expression d++, it generates the member-function call
d.operator ++(0)
  • the argument 0 is strictly a “a dummy value” that enables the compiler to distinguish between the prefic and postfic increment operator functions.
  • when implemented as the global function the prototype can be
Date operator ++(Date &,0)

22.11 explict constructors

  • use the keyword in the constructor
explict Array(int = 10);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值