第三章 类与对象应用

学习目的

  • 掌握静态数据成员及静态成员函数的使用;
  • 掌握友元函数的使用;
  • 掌握常成员函数的应用;
  • 掌握对象成员的使用;
  • 掌握C++11中移动复制构造函数、委托构造函数等语言扩展机制。

实习任务

  • 实习任务一

  1. 调试运行下面的程序,记录程序运行结果
#include <iostream> 
#include <string> 
using namespace std; 
class Mouse{
public:
    Mouse( string newName ); ~Mouse();
    string getName() { 
        return name; 
    } 
    static int mouseNum;/*static int 不会随着函数的结束而销毁*/
private:
    string name;
};
int Mouse::mouseNum = 0;
Mouse::Mouse( string newName ) : name(newName){
    cout<<name<<" is born!\n";
    mouseNum++; 
}
Mouse::~Mouse(){ 
    cout<<name<<" is gone...\n";
    mouseNum--; 
}
class Cat{ 
public:
    Cat( const string& newName): name(newName){ 
        cout<<name<<" is coming!\n";
    }
    void catchMouse( Mouse *pMouse); 
private:
    string name; 
};
    void Cat::catchMouse( Mouse *pMouse){
        cout<<"I catch you! I never want to see you again. "<<pMouse->getName()<<" !"<<endl; 
    delete pMouse;
}
int main()
{
    Cat cat("Black Cat Detective");
    Mouse *pMouse1 = new Mouse("Micky"); 
    cout<<Mouse::mouseNum<<" mouse left.\n"; 
    Mouse *pMouse2 = new Mouse("Xiaohua"); 
    cout<<Mouse::mouseNum<<" mouse left.\n"; 
    cat.catchMouse(pMouse2); 
    cout<<Mouse::mouseNum<<" mouse left.\n"; 
    cat.catchMouse(pMouse1); 
    cout<<Mouse::mouseNum<<" mouse left.\n"; 
    return 0;
}

static 在main里面的区别不大,其它函数里面区别很大,static变量能保持上次调用后的结果,int在函数返回后就销毁了,下次调用又重新建立。如:

#include <iostream>
void add(){
    static int a = 0;
    std::cout<<a;
    a++;
}
int main()
{
    for(int i=0;i<10;i++){
        add();
    }
    return 0;
}
运行结果:0123456789[Finished in 0.3s]
运行结果:
Black Cat Detective is coming!
Micky is born!
1 mouse left.
Xiaohua is born!
2 mouse left.
I catch you! I never want to see you again. Xiaohua !
Xiaohua is gone...
1 mouse left.
I catch you! I never want to see you again. Micky !
Micky is gone...
0 mouse left.
[Finished in 0.3s]

2.调试运行下面的程序,记录程序运行结果

#include <iostream> 
using namespace std; 
class TestClass{ 
public:
    TestClass( int newValue=0) {
    value = newValue;
    cout<<"Value: "<<value<<", Constructed!\n";
    }
    TestClass( const TestClass & rhs){
        value = rhs.value;
        cout<<"Value: "<<value<<", Copy Constructed!\n"; 
    }
    ~TestClass() { cout<<"Value: "<<value<<", Destructed!\n"; } void setValue( int newValue) { value = newValue; }
    int getValue()const { //常成员函数
        return value; 
    }
private:
    int value;
};
TestClass fooFun( TestClass t){
    t.setValue(20);
    return t; 
}
int main(){
    TestClass t1(10),t2(t1),t3; 
    t3=fooFun(t1);
    return 0;
}
运行结果
Value: 10, Constructed!
Value: 10, Copy Constructed!
Value: 0, Constructed!
Value: 10, Copy Constructed!
Value: 20, Copy Constructed!
Value: 20, Destructed!
Value: 20, Destructed!
Value: 20, Destructed!
Value: 10, Destructed!
Value: 10, Destructed!
[Finished in 0.3s]
  1. 将程序1中的fooFun传递对象作为参数和返回对象修改为传递引用以及返回引用,重新运行程序,记录运行结果。
TestClass & fooFun(TestClass &t){
    t.setValue(20);
    return t;
}
运行结果:
Value: 10, Constructed!
Value: 10, Copy Constructed!
Value: 0, Constructed!
Value: 20, Destructed!
Value: 10, Destructed!
Value: 20, Destructed!
[Finished in 0.5s]
  • 实习任务二

实习 2 中的分数类还很不完善,请按照下面定义和要求完善分数类。

  1. 将 Complex 类中的 getDoubleValue、getNum、getDen、output 定义为常成员函数。将构造函数的实现写成初始化列表的形式。
  2. 添加常成员函数 add,实现复数相加计算,计算结果返回一个新的复数对象,为Complex类型。
  3. 添加成员函数 multiply,实现当前复数的向量放大计算,实部和虚部同时放大,返回类型为 void。

常成员函数是指由const修饰符修饰的成员函数,在常成员函数中不得修改类中的任何数据成员的值。

#include <iostream>
#include <cmath>
using namespace std;
class Complex{
public:
    // Complex(){
    //     real = 0;
    //     image = 0;
    // }
    // Complex(double n){
    //     real = n;
    //     image = 0;
    // }
    Complex(double n=0, double d=0){
        real = n;
        image = d;
    }
    void setValue(double n, double d){
        real = n;
        image = d;
    }
    Complex add(const Complex &c )const{
        Complex x;
        x.setValue(real+c.getReal(), image+c.getImage());
        return x;
    }
    double getReal()const{
        return real;
    }
    double getImage()const{
        return image;
    }
    double getDistance()const{
        return sqrt(pow(real,2)-pow(image,2));
    }
    void multiply(double c){
        setValue(real*c, image*c);
    }
    void output()const{
        if(image == 0 && real != 0){
            cout<<real<<endl;
        }
        else if(image !=0 && real ==0){
            cout<<image<<'i'<<endl;
        }
        else if(image == 0 && real == 0){
            cout<<0<<endl;
        }
        else{
            if(image<0){
                cout<<real<<image<<'i'<<endl;
            }
            else{
                cout<<real<<'+'<<image<<'i'<<endl;
            }
        }
    }
private:
    double real;
    double image;
};
int main(){
    Complex c1, c2(2), c3(3,4);
    c1.output();
    c2.output();
    c3.output();
    c3.multiply(3);
    c3.output();
    c2.add(c3).output();
    c1.setValue(6,4);
    c1.output();
    cout<<c1.getDistance()<<endl;

    return 0;
}
运行结果:
0
2
3+4i
9+12i
11+12i
6+4i
4.47214
[Finished in 0.3s]
  • 实习任务三

  1. 完善实习2中的Time类
#include <iostream>
#include <cmath>
using namespace std;
class Time{
public:
    Time(){
        hour = 0;
        minute = 0;
        normalizeTime();
    }
    Time(int h, int m){
        hour = h;
        minute = m;
        normalizeTime();
    }
    Time(int minutes){
        hour = (minutes/60)%24;
        minute = minutes%60;
        normalizeTime();
    }
    void setTime(int h, int m){
        hour = h;
        minute = m;
        normalizeTime();
    }
    void output()const{
        
        cout<<hour<<':'<<minute<<endl;
    }
    int getHour()const{
        return hour;
    }
    int getMinute()const{
        return minute;
    }
    int getTotalMinutes()const{
        return hour*60 + minute;
    }
    Time getTimeSpan(const Time &t)const{
        Time x;
        int dis = abs(getTotalMinutes() - t.getTotalMinutes());
        x.setTime((dis/60)%24, dis%60);
        return x;
    }
private:
    int hour;
    int minute;
    void normalizeTime(){
        hour = ((60*hour + minute)/60)%24;
        minute = minute%60;
    }
};
int main(){
    Time t1(12, 75);
    t1.output();
    t1.setTime(8, 65);
    t1.output();
    Time t2(12, 13);
    t1.getTimeSpan(t2).output();
    cout<<"t1 Hour:"<<t1.getHour()<<endl;
    cout<<"t1 Minute:"<<t1.getMinute()<<endl;
    cout<<"t1 getTotalMinutes:"<<t1.getTotalMinutes()<<endl;

    return 0;
}
运行结果:
13:15
9:5
3:8
t1 Hour:9
t1 Minute:5
t1 getTotalMinutes:545
[Finished in 0.3s]
  1. 停车收费问题
class ParkingCard{
public:
    ParkingCard(double newRate){
        rate = newRate;
    }
    void setRate(double newRate){
        rate = newRate;
    }
    double getRate()const{
        return rate;
    }
    void setParkingTime(const Time &time){
        parkingTime.setTime(time.getHour(), time.getMinute());
    }
    void setLeavingTime(const Time &time){
        leavingTime.setTime(time.getHour(), time.getMinute());
    }
    double getTotalExpenses()const{
        Time x = parkingTime.getTimeSpan(leavingTime);
        return x.getTotalMinutes()*(rate/60.0);
    }
    void output()const{
        cout<<"Your parking time: ";
        parkingTime.output();
        cout<<"Our parking rate: ";
        cout<<rate<<endl;
        cout<<"Your total expenses: ";
        cout<<getTotalExpenses()<<endl<<endl;
    }
private:
    double rate;
    Time parkingTime;
    Time leavingTime;
};
int main(){
    ParkingCard card(5);
    card.setParkingTime(Time(9,20));
    card.setLeavingTime(Time(11,35));
    cout<<"Expenses:"<<card.getTotalExpenses()<<endl;
    cout<<"Detailed info:\n";
    card.output();
    return 0;
}
运行结果:
Expenses:11.25
Detailed info:
Your parking time: 9:20
Our parking rate: 5
Your total expenses: 11.25

[Finished in 0.3s]
  • 实习任务四

  1. Point 类?
#include <iostream>
#include <cmath>
using namespace std;
class Point{
public:
    Point():x(0), y(0){}//初始化列表
    Point(double newX, double newY){
        setValue(newX, newY);
    }
    Point(const Point &p){
        setValue(p.getX(), p.getY());
    }
    
    //~Point();
    void setValue(double newX, double newY){
        x = newX;
        y = newY;
    }
    double getX()const{return x;}
    double getY()const{return y;}
    double getDistance(const Point &p2)const{
        return sqrt(pow(x-p2.getX(),2)+pow(y-p2.getY(),2));
    }
    friend double getDistance(const Point &p1, const Point &p2){
                return sqrt(pow(p1.getX()-p2.getX(),2)+pow(p1.getY()-p2.getY(),2));
    }//友元函数
private:
    double x,y;
};

int main()
{
    Point p1(3,4);
    Point p2(5,2);
    double distance = p1.getDistance(p2);
    cout<<"Distance:"<<distance<<endl;
    distance = getDistance(p1,p2);
    cout<<"Distance:"<<distance<<endl;
    return 0;
}
运行结果:
Distance:2.82843
Distance:2.82843
[Finished in 0.4s]
  1. 三角形类
#include <iostream>
#include <cmath>
using namespace std;
class Point{
public:
    Point():x(0), y(0){}//初始化列表
    Point(double newX, double newY){
        setValue(newX, newY);
    }
    Point(const Point &p){
        setValue(p.getX(), p.getY());
    }
    
    ~Point(){}
    void setValue(double newX, double newY){
        x = newX;
        y = newY;
    }
    double getX()const{return x;}
    double getY()const{return y;}
    double getDistance(const Point &p2)const{
        return sqrt(pow(x-p2.getX(),2)+pow(y-p2.getY(),2));
    }
    friend double getDistance(const Point &p1, const Point &p2){
                return sqrt(pow(p1.getX()-p2.getX(),2)+pow(p1.getY()-p2.getY(),2));
    }//友元函数
private:
    double x,y;
};
class Triangle{
public:
    Triangle(const Point &p1, const Point &p2, const Point &p3){
        this->p1 = p1;
        this->p2 = p2;
        this->p3 = p3;
    }
    double getArea()const{
        return abs((1/2.0)*(p1.getX()*p2.getY()-p1.getY()*p3.getX()-p1.getY()*p2.getX()*p3.getY()+p3.getX()*p2.getY()+p1.getX()*p3.getY()+p2.getX()*p1.getY()));
    }
    double getPerimeter()const{
        return getDistance(p1,p2)+getDistance(p2,p3)+getDistance(p1,p3);
    }
private:
    Point p1, p2, p3;
};
int main()
{
    Point p1(0,0), p2(0,3), p3(4,0);
    Triangle t(p1, p2, p3);
    cout<<"Area:"<<t.getArea()<<endl;
    cout<<"Perimeter:"<<t.getPerimeter()<<endl;
    return 0;
}
运行结果:
Area:6
Perimeter:12
[Finished in 0.3s]
  • 课后练习

#include <iostream> 
using namespace std; 
class Example{ 
private:
    int i; 
public:
    Example(int n) { 
        i=n;
        cout<<"Constructing. "<<endl; 
    }
    ~Example() { 
        cout<<"Destructing. "<<endl; 
    }
    int get_i() { 
        return i; 
    } 
};
    int sqrt_it(Example o) { 
        return o.get_i()*o.get_i();
}
int main()
{
    Example x(10); 
    cout<<x. get_i()<<endl; 
    cout<<sqrt_it(x)<<endl; 
    return 0;
}
运行结果:
Distance:2.82843
Distance:2.82843
[Finished in 0.3s]
#include <iostream>
using namespace std; 
class Test{
public:
    Test() { 
        cout<<"Default constructor."<<endl; 
    } 
    Test(const Test& t){ 
        cout<<"Copy constructor!"<<endl; 
    }
};
void fun(Test p) {} 
int main(){
    Test a; 
    fun(a); 
    return 0;
}
运行结果:
Default constructor.
Copy constructor!
[Finished in 0.3s]
#include <iostream> 
using namespace std; 
class Dog{
public:
    static int number; 
    Dog(){
    number++;
    cout<<"New Dog"<<endl; 
}
    ~Dog(){ 
        number--;
        cout<<"A Dog Die"<<endl; 
    }
};
int Dog::number=0; 
int main(){
    Dog dog;
    Dog *pDog=new Dog(); 
    delete pDog;
    cout<<Dog::number<<endl; 
    return 0;
}
运行结果:
New Dog
New Dog
A Dog Die
1
A Dog Die
[Finished in 0.3s]
#include <iostream> 
using namespace std; 
class Test{
public:
    Test(int xx=1):x(xx){}
    void output()const{cout<<"x:"<<x<<endl;
} 
private:
    int x; 
};
int main()
{ 
    Test t;
    t.output(); 
    t=4; //尽量不要这么写!
    t.output(); 
    return 0;
}
运行结果:
x:1
x:4
[Finished in 0.3s]
#include <iostream> 
using namespace std; 
class Test{
public:
    Test(){
        cout<<"Default Constructor\n";
    }
    Test(int xx):x(xx){
        cout<<"Int Constructor\n";
    } 
    Test(const Test& t):x(t.x){//直接使用t的私有变量
        cout<<"Copy Constructor\n";
    }
private: 
    int x;
};
Test t;
int main(){
    cout<<"--------------------\n"; Test tt(t);
    return 0;
}
运行结果:
Default Constructor
--------------------
Copy Constructor
[Finished in 0.3s]
  1. 不标明private,默认private?
#include <iostream> 
using namespace std; 
class Point {
    int x,y; 
public:
    Point(int x1=0, int y1=0):x(x1), y(y1) { 
        cout<<"Point:"<<x<<' '<<y<<'\n';
}
    ~Point() {
        cout<<"Point destructor!\n"; }
};
class Circle {
    Point center;//圆心位置
    int radius;//半径 
//私有!
public:
    Circle(int cx,int cy, int r):center(cx,cy),radius(r) { 
        cout<<"Circle radius:"<<radius<<'\n';
    }
    ~Circle() {
        cout<<"Circle destructor!\n";
    } 
};
int main(){
    Circle c(3,4,5); 
    return 0;
}
运行结果:
Point:3 4
Circle radius:5
Circle destructor!
Point destructor!
[Finished in 0.3s]
#include <iostream> 
using namespace std; 
class Test{
public:
    Test(){ 
        cout<<"Hello: "<<++i<<endl; 
    }
    static int i; 
};
int Test::i=0; 
int main(){
    Test t[2];
    Test *p; 
    p=new Test[2]; 
    return 0;
}
运行结果:
Hello: 1
Hello: 2
Hello: 3
Hello: 4
[Finished in 0.3s]
#include <iostream> 
#include <string> 
using namespace std; 
class Person{ 
private:
    string name;
    int age; 
public:
    Person(string name,int age); 
    ~Person(){
        cout<<"Bye! My name is "<<name<<", I'm "<<age<<" years old."<<endl;
    }
    void growup(){ 
        age++; 
    }
};
Person::Person(string name, int age){
    this->name = name;
    this->age = age;
    cout<<"Hello,"<<name<<" is comming!"<<endl;
}
int main(){
    Person p("zhang",1); 
    for(int i=0;i<90;++i) 
        p.growup();
    return 0; 
}
运行结果:
Hello,zhang is comming!
Bye! My name is zhang, I'm 91 years old.
[Finished in 0.3s]
  1. 下面的程序无法通过编译,分析原因并出修改办法。
#include <iostream>
#include <vector> 
class Test{ 
private:
    int a; 
public:
    Test(const Test& t)=default; 
};
int main(){
    Test t;
    return 0; 
}

本来编译器会给类默认添加一个Test(){},如果使用过了“default”,编译器就不会再添加。把public下的Test(cosnt Test &t) = default注释掉,或者在前添加Test(){}就可通过编译。

#include <iostream>
using namespace std;
class Test{
private:
    int a,b;
public:
    Test():Test(1){
        cout<<"Constructor without parameter!\n";
    }
    Test(int x):Test(x,10){
        cout<<"Constructor with 1 parameter!\n";
    }
    Test(int x,int y):a(x),b(y){
        cout<<"Constructor with 2 paramter!\n";
    }
    void output()const{
        cout<<a<<","<<b<<endl;
    }
};
int main(){
    Test t;
    t.output();
    Test t1(3,5);
    t1.output();
    return 0;
}
运行结果:
Constructor with 2 paramter!
Constructor with 1 parameter!
Constructor without parameter!
1,10
Constructor with 2 paramter!
3,5
Program ended with exit code: 0
#include <iostream>
using namespace std;
class Test{
private:
    int a;
public:
    Test(){
        cout<<"Default constructor!\n";
    }
    Test(int x):a(x){
        cout<<"Constructor!\n";
    }
    Test(const Test& t){
        a=t.a;
        cout<<"Copy constructor!\n";
    }
    Test(Test && t){
        a=t.a;
        cout<<"move copy constructor!\n";
    }
};
Test fun(){
    return Test(3);
}
int main(){
    Test t;
    Test t2=move(fun());
    return 0;
}
运行结果:
Default constructor!
Constructor!
move copy constructor!
Program ended with exit code: 0
#include <iostream>
#include <vector>
using namespace std;
class Element{
private:
    int a;
public:
    Element(int e=0):a(e){}
    Element(const Element& e):Element(e.a){
        cout<<"Copy constructor!\n";} Element(Element&& e):Element(e.a){cout<<"Move copy constructor!\n";
        }
};
int main(){
    vector<Element> vec;
    vec.reserve(10);
    vec.push_back(Element(3));
    Element e(5);
    vec.push_back(e);
    return 0;
}
运行结果:
Move copy constructor!
Copy constructor!
Program ended with exit code: 0
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • 原文出处:南峰子的技术博客 Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了...
    _烩面_阅读 1,222评论 1 5
  • Objective-C语言是一门动态语言,他将很多静态语言在编译和链接时期做的事情放到了运行时来处理。这种动态语言...
    tigger丨阅读 1,390评论 0 8
  • 傍晚,隔壁的大爷大妈突然争执起来,起因是一只八哥。大妈把八哥放了,但是把八哥的翅膀弄伤了,八哥飞不起来,大爷去帮八...
    孤烛琉璃阅读 268评论 0 0
  • 低调做人。高调做事。 表现自己 梦在远方,路在脚下。 队长李一鸣寄语...
    遇见久伴阅读 305评论 0 0