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的主要内容,如果未能解决你的问题,请参考以下文章

Review cpp day10

Review cpp day09

Review cpp day07

Review cpp day08

Review cpp day06

Review cpp day05