您的位置:首页 > 编程语言 > C语言/C++

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

2017-02-02 21:32 1211 查看
一、对象数组的定义和初始化

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\n", 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("\r%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("\r%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 << "。\n";
}
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 << "时间到了,起床!\n";
}

#include "clock.h"
int main(void) {
Clock c(time(NULL));
//  c.run();
c.alarmRun(10, 31, 0);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++
相关文章推荐