入门客AI创业平台(我带你入门,你带我飞行)
博文笔记

C++:对象数组、对象动态申请和释放、类的定义和实现分开、this指针、常成员函数、时钟

创建时间:2017-02-02 投稿人: 浏览次数:150
一、对象数组的定义和初始化
1. 对象数组的创建方法:   //常量都是无名对象
1)类类型 数组名[元素个数];
2)类类型 数组名[元素个数] = { 数组的初始化列表... };
2. 说明:
1)在没有初始化列表的数组中,所有对象默认调用无参的构造函数。
2)对于有初始化列表的数组中,可以用构造函数来生成"类类型"的无名对象来初始化数组内的元素。
/** 代码演示 **/
#include <iostream>
using namespace std;
class Student {
public:
    Student(const string & n = "无名", double s = 0.0)
    : name(n), score(s) {   }
    void printInfo() {
        cout << "我叫" << name << ",我的成绩" << score << endl;
    }
private:
    string name;
    double score;
};
int main(void) {
    //int arr2[3] = {1, 2};
    Student arr2[3] = {Student(), Student("赵云", 97)};
    for(int i = 0; i < 3; i++) {
        arr2[i].printInfo();
    }
    cout << "------------" << endl;
    //int arr[10]; //等同如下
    Student arr[10];
    for(int i = 0; i < 10; i++) {
        arr[i].printInfo();
    }
    return 0;
}

二、对象的动态申请和释放
1. new/delete 来申请和释放单个对象
1)new 类类型
2)new 类类型(实参表)
2. new[]/delete[] 来动态创建对象数组
new 类名[元素个数];
说明:new[] 只能以无参形势调用相应的构造函数
3. new 和 malloc 区别
malloc之分配内存空间,new 做了两件事:
1)用malloc分配内存空间 //malloc是由系统来提供和分配的
2)调用构造函数来初始化这个空间所存放的对象
/** 代码演示 **/
#include <iostream>
using namespace std;
class Student {
public:
    Student(const string & n = "无名", double s = 0.0)
    : name(n), score(s) {   }
    void printInfo() {
        cout << "我叫" << name << ",我的成绩" << score << endl;
    }
    void setNameScore(const string & n, const double s) {
        name = n;
        if(s < 0 || s > 100.0) //数据校验,保证数据安全
            return ;
        score = s;
    }
private:
    string name;
    double score;
};
int main(void) {
    Student * ps = new Student;
    ps->printInfo();
    delete ps;
    ps = new Student("张飞", 60);
    ps->printInfo();
    delete ps;
    //以下创建动态对象数组
    ps = new Student[3]; //创建的时候不能初始化,C11可初始化(不常用)
    ps[0] = Student("张飞", 60);
    ps[1].setNameScore("关羽", 70);
    ps[2] = Student("刘备", 80);
    for(int i = 0; i < 3; i++) {
        ps[i].printInfo();
    }
    delete[] ps;
    ps = NULL;
    return 0;
}

【练习:实现一个电子始终类 Clock类】
#include <time.h>
time_t time(time_t *t);
//time_t (unsigned long long) 返回 1970-01-01 00:00:00 至今的秒数
将time_t转换为年月日十分秒的方法:
time_t tt = time(NULL);
struct tm *p = localtime( &tt ); //&tt是地址
p->tm_hour; //小时,整型值
p->tm_min; //分钟,整型值
p->tm_sec; //秒,整型值
time_t tt = time(0); struct tm *time = localtime(&tt);
printf("%4d-%02d-%02d ", time->tm_year+1900,time->tm_mon+1,time->tm_mday); //打印年月日
class Clock {
public:
void run() {
//循环
while(1) {
//打印当前的时间 00:00:00
sleep(1);
//将second成员加1秒
}
}
成员:小时hour、分钟minute、秒second
}
int main(void) {
Clock c( time(NULL) ); //time(NULL) 设置时钟的起始时间
c.run(); //让时间运行
return 0;
}
/** 代码演示 - teacher **/
#include <stdio.h>
using namespace std;
class Clock {
public:
    Clock(time_t tt = 0) { //1970-01-01 00:00:00
        struct tm *p = localtime(&tt);
        hour = p->tm_hour;
        minute = p->tm_min;
        second = p->tm_sec;
    }
    void run() {
        while(1) {
            showTime();//显示时间
            tick(); //滴答,时间+1s
        }
    }
private:
    void tick() {
        sleep(1);
        ++second;
        //时间校正算法:
        minute += second/60; //0 or 1
        second %= 60;//second不超过60
        hour += minute/60;//0 or 1
        minute %= 60;//minute不超过60
        hour %= 24;//hour不超过24
    }
    void showTime() {
        printf("
%02d : %02d : %02d", hour, minute, second);
        fflush(stdout);
    }
private:
    short hour;
    short minute;
    short second;
};
int main(void) {
    Clock c(time(NULL));
    c.run();
    return 0;
}

三、类的定义和实现分开
1. 成员函数的实现有两种方式:
1)类内声明,类内实现
2)类内声明,类外实现  /** 代码演示如下 **/
类内声明的方法不变;
类外实现的时候,"函数名前要加作用域的限定"。
如果函数形参表带有缺省实参,只能保留一个地方带有缺省实参,建议:将"缺省实参写在声明的地方"。
3)实现和声明分开:
时钟例子:"多文件编程"
clock.cpp //类的实现  #include "clock.h"
clock.h //类的声明、头文件声明、条件编译
main.cpp (主函数) // #include "clock.h"
$: ls
clock.cpp  clock.h  main.cpp
$: g++ clock.cpp main.cpp -o myclock
$: myclock
 16 : 38 : 43
/** 三、1. 2)类内声明,类外实现 **/
#include <iostream>
#include <time.h>
#include <stdio.h>
using namespace std;
class Clock {
public:
    Clock(time_t tt = 0);
    void run();
private:
    void showTime();
    void tick();
private:
    short hour;
    short minute;
    short second;
};
Clock::Clock(time_t tt) { //类外声明不能加默认实参
    struct tm *p = localtime(&tt);
    hour = p->tm_hour;
    minute = p->tm_min;
    second = p->tm_sec;
}
void Clock::run() { //在函数名前加作用域限定符
    while(1) {
        showTime();
        tick();
    }
}
void Clock::tick() {
    sleep(1);
    ++second;
    minute += second/60;
    second %= 60;
    hour += minute/60;
    minute %= 60;
    hour %= 24;
}
void Clock::showTime() {
    printf("
%02d : %02d : %02d", hour, minute, second);
    fflush(stdout);
}
int main(void) {
    Clock c(time(NULL));
    c.run();
    return 0;
}

四、this 指针
1. 在类内总有一个已定义的指针 this ,在成员函数调用时,this 指向调用这个函数的对象。
2. 作用:
1)用来区分一个对象内"标识符"的作用域;
2)成员函数可以用 this 返回调用对象的地址;
3)成员函数可以用 this 返回调用对象自身的引用;
4)成员函数可以用 this 指针来销毁自身;
3. 说明:
1)this 只能在成员函数内调用;
2)在C++编译器中只有一个 this 哪个对象在调用成员函数时,这个 this 就指向那个对象;
3)this 不占用对象的存储空间。
/** 代码演示 **/
#include <iostream>
using namespace std;
class Teacher {
public:
    Teacher(string name, int a) {
        this->name = name; //this不占用对象的空间,1)区分标识符作用域
        age = a;
        cout << "Teacher() this =" << this << endl;
    }
    void printInfo() {
        cout << "printInfo() this =" << this << endl;
        cout << "我叫" << name << ",今年" << age << "。
";
    }
    Teacher * getMySelf() { return this; } //2)返回调用对象地址
    Teacher & getSelf() { return *this; } //3)返回调用对象的引用
    void freeSelf() {
        cout << "delete " << this << endl;
        delete this; } //4)销毁自身
private:
    string name; //封装了指针,4个字节
    int age; //4个字节
};
int main(void) {
    Teacher t1("老魏", 40);
    t1.printInfo();
    cout << "&t1 = " << &t1 << endl;
    cout << "t1.getMySelf() = " << t1.getMySelf() << endl;
    Teacher & rt1 = t1.getSelf();
    rt1.printInfo();
    //4)以下示意对象销毁自身
    Teacher *p = new Teacher("孔明", 40);
    cout << "p = " << p << endl;
    p->freeSelf();
    cout << "---------------------" << endl;
    Teacher t2("老王", 30);
    t2.printInfo();
    cout << "&t2 = " << &t2 << endl;
    cout << "sizeof(t1)" << sizeof(t1) << endl;//8
    return 0;
}

五、常成员函数
1. 常成员函数的语法形式:
类型 成员函数名 (形参表) [ const ] [ throw 列表 ] { ... }
具有 const 修饰的成员函数叫"常成员函数"。
2. 作用:
1)一个有常属性的对象只能调用常成员函数;
2)一个常成员函数不能修改对象内的成员,否则报错。"只读"
3. 说明:
1)具有常属性的对象只能调用常成员函数;
2)没有常属性的对象可以调用常成员函数,也能够调用普通成员函数,但会优先调用普通成员函数;
3)有常属性的成员函数与普通成员函数可以构成重载;
4)常成员函数不能修改对象自身的成员;
5)常成员函数不能返回非 const 属性的成员的引用(包括指针);
/** 代码演示 **/
#include <iostream>
using namespace std;
class Person {
public:
    Person(const string & n): name(n) {}
    void printInfo() { //重载,优先普通成员函数
        cout << "我是普通的" << name << endl;
    }
    void printInfo() const {
        cout << "const我叫" << name << endl;
    }
    const string & getName() const { return name; }
    void setName(const string & n) {
        name = n;
    }
private:
    string name;
};
int main(void) {
    const Person p("小张");
    p.printInfo();
//  p.setName("张飞"); //出错,因为p为常对象
    Person p2("小李");
    p2.setName("李某某");
    p2.printInfo();
    const string & alias = p.getName();
//  alias = "李四";
    p2.printInfo();
    return 0;
}

六、 mutable 关键字(变化的)
在具有常属性的成员函数中,不能修改成员对象的值,但有 mutable 修饰的成员对象除外。
/** 代码演示 **/
class Person {
public:
    Person(const string & n): name(n), count(0) {}
private:
    string name;
    mutable int count; //不受成员函数const限定符的限制
};
int main(void) {
    const Person p("小张");
    p.printInfo();
    const string & alias = p.getName();
    alias = "小李"; //报错!!!
    p.printInfo();
    return 0;
}

作业:
写过的时钟类,改为定时器,进行定时后,在时间到来时,做相应的事儿。
/** 【时钟案例】增加代码 **/
void Clock::alarmRun(short h, short m, short s) {
    while(1) {
        showTime();
        if(hour == h && minute == m && second == s) {
            doSomething();
            return;
        }   
        tick();
    }   
}
void Clock::doSomething() {
    cout << "时间到了,起床!
";
}

#include "clock.h"
int main(void) {
    Clock c(time(NULL));
//  c.run();
    c.alarmRun(10, 31, 0); 
    return 0;
}


声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。