Review cpp day03
Posted 达少Rising
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Review cpp day03相关的知识,希望对你有一定的参考价值。
回顾:
Review cpp day01
Review cpp day02
十一、类型转换
1、隐式转换
char c = 'a';
int i = c;//隐式转换
void func(int i) {...}
func(c);//隐式转换
int foo(void){
char c = 'a';
return c;//隐式转换
}
2、显式转换
2.1、C++兼容C的强制类型转换
char c = 'a';
int i = (int)c;//显式转换C风格
int i = int(c);//C++风格
2.2、C++增加了四种操作符形式的类型转换
- 1)静态类型转换
- 语法:目标类型变量 = static_cast<目标类型>(源类型变量);
- 适用场景:用于将void*转为其它类型的指针。
05static_cast.cpp
#include <iostream>
using namespace std;
int main(void){
int *pi = NULL;
//char c = (int)pi;//C风格
//char c = int(pi);//C++风格
//char c = static_cast<int>(pi);//error,产生错误提示
void* pv = pi;
//pi = pv;//error
pi = stactic_cast<int*>(pv);
return 0;
}
-
2)动态类型转换(后面讲)
- 语法:目标类型变量 = dynamic_cast<目标类型>(源类型变量);
-
3)常类型转换
- 语法:目标类型变量 = const_cast<目标类型>(源类型变量);
- 适用场景:用于去除一个指针或引用的常属性
eg:
const int a = 0; const int* pa = &a; *pa = 200//error //---------------------------------- int* pa2 = const_cast<int*>(&a); *pa2 = 200;//ok
06const_cast.cpp
#include <iostream>
using namespace std;
int main(void){
/*
*volatile 修饰变量表示是易变的,告诉编译器每次再次使用该变量都要从内存中
*重新加载,而不要取寄存器中的副本,防止因为编译器优化引发的错误结果
**/
//const int ci = 100;//1
const volatile int ci = 100;//2
//int* pci = &ci;//error,相当于权限扩大了
int* pci = const_cast<int*>(&ci);
*pci = 200;
cout << "&ci=" << (void*)&ci << endl;//加(void*)防止编译器将结果转成bool(&ci=1)类型输出
cout << "pci=" << pci << endl;//输出结果一样的地址
cout << "ci=" << ci <<endl;//1 ci=100 2 ci=200
cout << "*pci=" << *pci << endl;//*pci=200
}
- 4)重解析类型转换
- 语法:目标类型变量 = reinterpret_cast<目标类型>(源类型变量);
- 适用场景:
- 任意类型指针或引用之间转换
- 在指针和整型数之间进行转换
适用场景eg1:
07reinterpret_cast.cpp
#include <iostream>
using namespace std;
int main(void){
struct T{
char type[5];
char id[9];
char passwd[7];
};
//"\\000" == '\\0' == 0
char buf[] = "0001\\00012345678\\000123456";
T* pt = reinterpret_cast<T*>(buf);
cout << pt->type << endl;//0001
cout << pt->id << endl;//12345678
cout << pt->passwd << endl;//123456
return 0;
}
适用场景eg2:
向物理内存0x12345678存放数据100;
int* paddr = reinterpret_cast<int *>(0x12345678);
*paddr = 100;
到此为止:前面的内容是对C的扩充知识,后面的内容就是C++的编程思想面向对象编程
小结:C++之父给C程序的建议
- 1、慎用宏,可以使用const、enum、inline替换
eg:
#define PAI 3.14
// ==>
const double PAI = 3.14;
#define STATE_SLEEP 0
#define STATE_RUN 1
#define STATE_STOP 2
//==>
enum STATE{SLEEP, RUN, STOP0};
#define max(a, b) ((a) > (b) ? (a) : (b))
//==>
inline int max(int a, int b){return a > b ? a : b;}
- 2、变量随用随声明同时初始化
- 3、尽量使用new/delete替换malloc/free
- 4、少用void*、指针计算、联合体、强制转换
- 5、尽量使用string表示字符串,少用C风格char*
十二、类和对象//了解
-
1、什么是对象?万物皆对象,任何一种都可以看作是对象
-
2、如何描述对象?通过对象的属性(名词、数量词、形容词)和行为(动词)来描述对象。
eg:描述冰箱对象
属性:品牌、容量、颜色、功耗
行为:装东西、冷冻、冷藏 -
3、面向对象的程序设计
对自然世界中对象的描述引入到编程实践的方法,这种方法称为“数据抽象”,即在描述对象时把细节的东西剥离出去,只考虑一般性的、有规律性的、统一的东西。 -
4、什么是类?
类是将多个对象的共性提取出来定义的新的数据类型,是对对象属性和行为的抽象描述。
十三、类的定义和实例化
1、类的一般形式
class/struct 类名:继承方式 基类,.....{
访问控制属性:
类名(形参表):初始化表{}//构造函数
~类名(void){}//析构函数
返回类型 函数名(形参表){}//成员函数
数据类型 变量名;//成员变量
};
2、访问控制属性
- 1)public:公有成员,类的内部和外部都可以访问的成员
- 2)protected:保护成员(后面讲)
- 3)private:私有成员,只有在类的内部才可以访问成员
eg:
class A{
public:
int a;
int b;
private:
int c;
public:
int d;
};
- class和struct的区别?class的成员是private为了安全,struct的成员是public为了兼容结构体。
注: 使用class定义的类默认的访问控制属性是private,而使用struct定义的类默认的访问控制属性是public。
08class.cpp
#include <iostream>
using namespace std;
//原来叫定义结构体类型,现在叫定义类
//struct Student{
class Student{
private:
//属性:用成员变量描述
string m_name;
public:
//私有成员在类的内部不能直接访问,但是可以提供公有的函数来间接访问,
//在函数可以对非法数据加以限定,控制逻辑合理性
void setName(const string& name){
if(name=="二"){
cout << "你才二" << end;
}
else
m_name = name;
}
public:
int m_age;
int m_no;
//行为:用成员函数描述
void eat(const string& food){
cout << "我吃" << food << endl;
}
void sleep(int hour){
cout << "我睡了" << hour << "小时" << endl;
}
void learn(const string& course){
cout << "我在学" << course << endl;
}
void who(void){
cout << "我叫" << m_name << ",今年" <<
m_age << "岁,学号是" << m_no << endl;
}
};
int main(void){
//原来叫做定义结构体类型变量
//现在叫做创建对象,或实例化对象
Student s;
//s.m_name = "张飞";
s.setName("张翼德");
s.m_age = 28;
s.m_no = 10086;
s.who();
s.eat("apple");
s.sleep(8);
s.learn("C++");
return 0;
}
3、构造函数(Constructor)
- 1)构造函数的函数名和类名相同,没有返回类型;
- 2)构造函数在创建对象时自动被调用,不能像普通成员函数一样直接去调用。
class 类名{
类名(构造形参表){
//主要负责对象的初始化
}
};
eg:
class A{
public:
A(int data){
m_data = data;
}
int m_data;
};
int main(void){
A a(10);
}
01constuctor.cpp
#include <iostream>
using namespace std;
class Student{
public:
Student(const string& name, int age, int id){
cout << "构造函数" << endl;
m_name = name;
m_age = age;
m_id = id;
}
void who(void){
cout << "我叫" << m_name << "今年" << m_age
<< "岁,学号是" << m_id << endl;
}
private:
string m_name;
int m_age;
int m_id;
};
int main(void){
//创建对象,构造函数将自动被调用
//(.....):指明构造函数需要的实参
Student s("张飞", 28. 10011);
s.who();
//构造函数不能先式地调用
//s.Student("张飞", 28. 10011);//error
return 0;
}
- 练习:实现一个电子时钟类,要求使用构造函数初始化当前的时间,以秒单位运行。
提示:
class Clock{
public:
Clock(time_t t){
//初始化成员变量
tm* local = localtime(&t);
m_hour = local->tm_hour;
...
}
void run(void){
while(1){
//打印当前时间
//计时+1秒:m_sec++
//sleep(1);
}
}
private:
int m_hour;
int m_min;
int m_sec;
};
02clock.cpp
#include <iostream>
#include <ctime>
#inlcude <cstdio>
#include <unistd.h>
using namespace std;
class Clock{
public:
Clock(time_t t){
tm* local = localtime(&t);
m_hour = local->tm_hour;
m_min = local->tm_min;
m_sec = local->tm_sec;
}
void run(void){
while(1){
printf("\\r%02d:%02d:%02d", m_hour, m_min, m_sec);
fflush(stdout);//刷新输出缓冲区
if(++m_sec == 60){
m_sec = 0;
if(++m_min == 60){
m_min = 0;
if(++m_hour ==24){
m_hour;
}
}
sleep(1);
}
}
private:
int m_hour;
int m_min;
int m_sec;
};
int main(void){
Clock clock(time(NULL));
clock.run();
return 0;
}
4、对象的创建和销毁
- 1)在栈区创建单个对象
类名 对象(构造实参表); 类名 对象 = 类名(构造实参表);//和上面等价
eg:
Student s("z", 28, 10011);
//<==>
Student s = Student("z", 28, 10011);
- 2)在栈区创建多个对象(对象数组)
类名 对象数组[元素个数] = {类名(构造实参表), ......};
eg:int arr[5] = {1, 2, 3, 4, 5};
Student sarr[3] = {
Student("貂蝉", 20, 10086),
Student("大乔", 25, 10087),
Student("小乔", 22, 10088)};
sarr[0].who();
sarr[1].who();
sarr[2].who();
- 3)在堆区创建单个对象
- 创建:
类名* 对象指针 = new 类名(构造实参 表); int* pi = new int(100);
- 销毁:
delete 对象指针; 对象指针 = NULL;
eg:
//在堆区创建单个对象
Student* ps = new Student("林黛玉", 19,12345);
ps->who();//(*ps).who()
delete ps;
ps = NULL;
- 4)在堆区创建对象数组
- 创建:
类名* 对象指针 = new 类名[元素个数]{类名(构造实参表),.....};
- 销毁:
delete[] 对象指针; 对象指针 = NULL;
eg:
//在堆区创建多个对象
Student* parr = new Student[3]{
Student("潘金莲", 35, 10011),
Student("扈三娘", 35, 10012),
Student("孙二娘", 40, 10013)};
parr[0].who();//(parr+0)->who()
parr[1].who();//(parr+1)->who()
parr[2].who();//(parr+2)->who()
delete[] parr;
parr = NULL;
5、多文件编程
- 类的声明和定义可以分别放在不同的文件中:
- 1)类的声明部分放在头文件xx.h
- 2)类的实现部分放在源程序xx.cpp
Clock.h
//类的声明
#ifndef __CLOCK_H_
#define __CLOCK_H_
#include <iostream>
#include <ctime>
#inlcude <cstdio>
#include <unistd.h>
using namespace std;
class Clock{
public:
Clock(time_t t);
void run(void);
private:
int m_hour;
int m_min;
int m_sec;
};
#endif//__CLOCK_H_
Clock.cpp
#include "Clock.h"
//类的实现
//需要在函数名字前面加“类名::”
Clock::Clock(time_t t){
tm* local = localtime(&t);
m_hour = local->hour;
m_min = local->min;
m_sec = local->sec;
}
void Clock::run(void){
while(1){
printf("\\r%02d:%02d:%02d", m_hour, m_min, m_sec);
ffush(stdout);//刷新输出缓冲区
if(++m_sec == 60){
m_sec = 0;
if(++m_min == 60){
m_min = 0;
if(++m_hour ==24){
m_hour = 0;
}
}
sleep(1);
}
}
main.cpp
#include "Clock.h"
int main(void){
Clock clock(time(NULL));
clock.run()
return 0;
}
Makefile
a.out:Clock.o main.o
g++ *.o
Clock.o:Clock.cpp
g++ -c Clock.cpp
main.o:mian.cpp
g++ -c main.cpp
clean:
rm *.o a.out
- Makefile的格式:
目标文件:依赖文件
命令
扩展练习V1.0:实现企业员工系统
- 需要:实现一个员工类
- 提示:
class/struct Employee{
行为:打印员工信息、计算工资
属性:姓名、工号、薪资
};
工资计算方式:基本工资+绩效工资
基本工资=薪资*出勤率(输入出勤天数/23.0)
绩效工资=基本工资一半
class Employee{
public:
string name;
int id;
private:
double sarary;
public:
void print(void){
cout << id << "," << name << endl;
}
void countSarary(int days){
double fun_sarary = 0;
double ex_sarary = 0;
cout << "请输入出勤天数:";
cin >> days;
fun_sarary = 4000 * (days / 23.0);
ex_sarary = fun_sarary / 2;
sarary = fun_sarary + ex_sarary;
}
};
int main(void){
Employee e;
return 0;
}
以上是关于Review cpp day03的主要内容,如果未能解决你的问题,请参考以下文章