实习工作日总结day3(2021.7.7)

day3

学习笔记

类和对象

  1. 面向对象编程思想

    • 任何一个事物可看成一个对象
    • 对象两要素:属性行为
  2. 面向对象三要素

    • 封装
    • 继承
    • 多态
  3. 类的声明

    #include <iostream>
    
    // 演示类的最基本使用方式,和struct一致
    struct DateStruct
    {
    	int year;
    	int month;
    	int day;
    };
    
    class DateClass
    {
    public:
    	int year;
    	int month;
    	int day;
    };
    
    // 演示类的成员函数
    class Date
    {
    public:
    	int year;
    	int month;
    	int day;
    
    	void print()
    	{
    		std::cout << year << "/" << month << "/" << day;
    	}
    
    	void printTwice()
    	{
    		// 成员函数可以相互调用
    		print();
    		print();
    	}
    };
    
    // 以下演示类的访问权限
    
    // 以上面的DateClass为例说明struct/class默认权限不同,class需显式指定public
    
    // 通过public接口访问私有成员
    class Time
    {
    public:
    	int getHour() const
    	{
    		return hour;//方便打断点调试(一个就好)
    	}
    	int getMinute() const
    	{
    		return minute;
    	}
    	int getSecond() const
    	{
    		return second;
    	}
    
    private://外部不能直接修改
    	int hour;
    	int minute;
    	int second;
    };
    
    // 权限控制粒度为类,而非对象
    class TimeWithCopy
    {
    public:
    	void copyFrom(const TimeWithCopy& src)//同类型对象能访问其private成员
    	{
    		hour = src.hour;
    		minute = src.minute;
    		second = src.second;
    	}
    
    private:
    	int hour;
    	int minute;
    	int second;
    };
    
    // 探讨public/private给我们带来了什么好处?
    // 1. 类的内部数据得到保护
    // 2. 类的使用方法更明确,不易出错
    // 3. 类的实现细节更容易修改
    // 4. 内部数据修改有了统一入口,更容易调试
    
    int main()
    {
    	{
    		DateClass date = { 2021, 4, 9 };
    		std::cout << date.year << "/" << date.month << "/" << date.day << std::endl;
    		date.day = 10;
    		std::cout << date.year << "/" << date.month << "/" << date.day << std::endl;
    	}
    
    	{
    		Date date = {2021, 4, 9};
    		date.print();
    	}
    
    	return 0;
    }
    
  4. 构造函数

    #include <iostream>
    
    // 类成员变量必须被显式初始化,否则处于未初始化状态,访问时会取到不可预料的值
    class Uninitialized
    {
    public:
    	int foo;
    	int bar;
    };
    
    // 有理数类,演示构造函数的用法
    class Rational
    {
    public:
    	// 默认构造函数
    	Rational()
    	{
    		numerator = 0;
    		denominator = 1;
    	}
    
    	// 带参数的构造函数
    	Rational(int n, int d)
    	{
    		numerator = n;
    		denominator = d != 0 ? d : 1;	// 分母不能为零
    	}
    
    	// 构造函数同样支持重载
    	Rational(float f)
    	{
    		// 浮点数转换为有理数实现较复杂,以下代码示意下
    		numerator = static_cast<int>(f);
    		denominator = 1;
    	}
    
    	float getFloat() const
    	{
    		float n = static_cast<float>(numerator);
    		float d = static_cast<float>(denominator);
    		return n / d;
    	}
    
    private:
    	int numerator;	// 分子
    	int denominator;	// 分母
    };
    
    // 添加自定义构造函数后隐式生成的默认构造函数将被取消
    class Foo
    {
    public:
    	Foo(int f)
    	{
    		foo = f;
    	}
    
    private:
    	int foo;
    };
    
    int main()
    {
    	// 新版本编译器会检测到引用未初始化变量会直接报编译错误
    	//Uninitialized unitialized;
    	//std::cout << unitialized.foo << " " << unitialized.bar << std::endl;
    
    	// 调用默认构造函数,初始化为0
    	Rational zero;
    	//Rational zero();	// 会被编译器当成函数声明
    
    	// 显式调用构造函数初始化为1/3
    	Rational r1(1, 3);
    	Rational r2 = {1, 3};	// initializer list, C++11特性
    
    	// 调用重载的构造函数
    	Rational r3(1.0f);
    
    	// 学生尝试:合并前两个构造函数
    
    	// 有明确的构造函数,默认构造函数不存在
    	//Foo f;
    
    	return 0;
    }
    
  5. 构造函数初始化

    #include <string>
    #include <vector>
    #include <map>
    
    // 构造函数中对成员变量赋值
    class AssignmentSample
    {
    public://编码习惯:添加成员要记得对每一个构造函数添加初始化
    	AssignmentSample(int v1, const std::string& v2)
    	{
    		var1 = v1;
    		var2 = v2;
    	}
    
    private:
    	int var1;
    	std::string var2;
    };
    
    // 构造函数初始化列表
    class InitializationListSample
    {
    public:
    	InitializationListSample(int v1, const std::string& v2) : var1(v1), var2(v2)
    	{
    	}
    
    private:
    	int var1;
    	std::string var2;
    };
    
    // 类声明时就地初始化,推荐此种方式
    class InClassSample
    {
    public:
    	// 构造函数中不必将所有成员变量再初始一遍了
    	InClassSample(int v1) : var1(v1)
    	{
    	}
    
    	InClassSample(const std::string& v2) : var2(v2)
    	{
    	}
    
    private:
    	// 假设成员变量很多
    	int var1 = 0;
    	std::string var2 = "foo";
    	bool var3 = false;
    	float var4 = 0.0f;
    	double var5 = 0.0;
    	// ... ...
    
    	// 不支持静态变量
    	//static int var6 = 0;
    	static const int var6 = 0;
    };
    
    // 自行验证三种初始化方式的优先顺序:
    // 1. 声明时初始化;
    // 2. 构造函数初始化列表;
    // 3. 构造函数体内赋值;
    
    int main()
    {
    	// 使用initializer list初始化容器
    	std::vector<std::string> names = { "James", "Kevin", "Steph", "Chris" };
    	std::map<std::string, int> scores = 
    	{
    		{ "James", 100 },
    		{ "Kevin", 99 },
    		{ "Steph", 98 },
    		{ "Chris", 97 }
    	};
    
    	// 使用initializer list初始化类,自动对应到相应构造函数
    	InClassSample foo = { 1 };
    	InClassSample bar = { "bar" };
    
    	return 0;
    }
    

    Quiz:https://www.geeksforgeeks.org/c-plus-plus-gq/constructors-gq/

  6. 析构函数

    #include <string.h>
    
    // 整型数组,析构函数中释放内存
    class IntArray
    {
    public:
    	IntArray(int len)
    	{
    		if (len > 0)
    		{
    			array = new int[len];
    			memset(array, 0, sizeof(int) * length);
    			length = len;
    		}
    	}
    
    	~IntArray()
    	{
    		// 注意delete nullptr是合法的
    		delete [] array;
    	}
    
    	void setValue(int index, int value)
    	{
    		if (index < length)
    			array[index] = value;
    	}
    
    	int getValue(int index) const
    	{
    		if (index < length)
    			return array[index];
    		else
    			return 0;
    	}
    
    	int getLength() const
    	{
    		return length;
    	}
    
    private:
    	int* array = nullptr;
    	int length = 0;
    };
    
    // 程序退出或模块卸载时析构
    IntArray baz(20);
    
    int main()
    {
    	// 栈中释放时析构
    	IntArray foo(10);
    
    	// delete时析构
    	IntArray* bar = new IntArray(5);
    	delete bar;
    
    	return 0;
    }
    

    Quiz:https://www.geeksforgeeks.org/c-plus-plus-gq/destructors-gq/

  7. 默认生成的函数

    • 默认默认构造函数
    • 默认析构函数
    • 拷贝构造函数
    • 复制操作符
    • 地址运算符
  8. 复制构造函数

    #include <string.h>
    
    // 以深拷贝为例演示拷贝构造函数
    class Copyable
    {
    public:
    	Copyable()
    	{
    		var2 = new int[10];
    	}
    	~Copyable()
    	{
    		delete [] var2;
    	}
    
    	//浅拷贝有时候会有问题delete时(指针)
    	// 拷贝构造函数
    	Copyable(const Copyable& copy)
    	{
    		var2 = new int[10];
    		memcpy(var2, copy.var2, sizeof(int) * 10);
    	}
    
    	// 赋值运算符
    	Copyable& operator=(const Copyable& copy)
    	{
    		var1 = copy.var1;
    
    		delete [] var2;//记得delete原来的内存空间
    		var2 = new int[10];
    		memcpy(var2, copy.var2, sizeof(int) * 10);
    
    		return *this;
    	}
    
    private:
    	int var1 = 0;
    	int* var2 = nullptr;
    };
    
    // 去掉默认生成的拷贝函数
    class Nocopyable
    {
    public:
    	Nocopyable(const Nocopyable& copy) = delete;
    	Nocopyable& operator=(const Nocopyable& copy) = delete;
    };
    
    int main()
    {
    	{
    		Copyable foo;
    		// 以下两种方式均会调用拷贝构造函数
    		Copyable bar(foo);
    		Copyable baz = foo;
    
    		// 触发赋值运算符函数
    		Copyable qux;
    		qux = foo;
    	}
    
    	{
    		// 默认生成的拷贝构造及赋值移除后不可调用
    		//Nocopyable foo;
    		//Nocopyable bar = foo;
    		//bar = foo;
    	}
    
    	return 0;
    }
    
  9. this指针

    • 指向对象自身首地址

    • 引用整个对象

      • *this
    • 仅能在类内部使用

      #include <iostream>
      
      // 以查看汇编代码的方式引入this指针
      class Printer
      {
      public:
      	// 查看汇编指令看到取ecx寄存器存入this指针
      	void printInt(int i)
      	{
      		std::cout << i << std::endl;
      		++intCount;
      	}
      
      	void printFloat(float f)
      	{
      		std::cout << f << std::endl;
      		++floatCount;
      	}
      
      	void printDouble(double d)
      	{
      		std::cout << d << std::endl;
      		++doubleCount;
      	}
      
      private:
      	int intCount = 0;
      	int floatCount = 0;
      	int doubleCount = 0;
      };
      
      // this指针的典型用法
      class ThisPointer
      {
      public:
      	ThisPointer(int a, float b, double c)
      	{
      		// this指针引用成员变量
      		this->a = a;
      		this->b = b;
      		this->c = c;
      
      		// this指针引用成员函数
      		this->init();
      	}
      
      private:
      	void init()
      	{
      		std::cout << __FUNCTION__ << std::endl;
      	}
      
      	int a;
      	float b;
      	double c;
      };
      
      int main()
      {
      	// 查看汇编代码看到函数调用时将p的指针存入ecx寄存器
      	Printer printer;
      	printer.printInt(0);
      	printer.printFloat(0.1f);
      	printer.printDouble(0.01);
      
      	// 以上成员函数的调用等价于以下普通函数调用
      	//printInt(&p, 0);
      
      	return 0;
      }
      

      Quiz:https://www.geeksforgeeks.org/c-plus-plus-gq/this-pointer-gq/

  10. static成员

    #include <iostream>
    
    // 以uid生成为例演示static成员
    class User
    {
    public:
    	User()
    	{
    		uid = ++total;
    	}
    
    	int getUserId() const
    	{
    		return uid;
    	}
    
    	static int getTotalUserCount()
    	{
    		// 静态成员函数不含this指针,无法访问成员变量
    		//std::cout << uid << std::endl;
    
    		return total;
    	}
    
    private:
    	int uid;
    	static int total;
    
    	// 非const静态成员变量无法在类定义中初始化
    	//static int total = 0;
    	static const int foo = 0;//const可以直接在里面初始化,否则只能在外面初始化
    };
    
    // 静态成员变量初始化
    int User::total = 0;
    
    int main()
    {
    	User usr1;
    	std::cout << "new user with uid #" << usr1.getUserId() << std::endl;
    
    	User usr2;
    	std::cout << "new user with uid #" << usr2.getUserId() << std::endl;
    
    	// 建议通过类名引用静态成员函数
    	std::cout << "there are " << User::getTotalUserCount() << " user(s) totally" << std::endl;
    
    	// 通过对象也可以引用静态成员函数
    	std::cout << usr1.getTotalUserCount() << usr2.getTotalUserCount() << std::endl;
    
    	return 0;
    }
    

    Quiz:https://www.geeksforgeeks.org/c-plus-plus-gq/static-keyword-gq/

  11. const成员函数:表示该函数不会修改成员

    #include <iostream>
    
    class Foo
    {
    public:
    	// const成员函数
    	int getBar() const
    	{
    		// 不可调用非const方法
    		//setBar(1);
    
    		return bar;
    	}
    
    	// 非const成员函数
    	void setBar(int v)
    	{
    		bar = v;
    	}
    
    private:
    	int bar = 0;
    
    public:
    	int baz = 0;
    };
    
    void tryConstFoo(const Foo& foo)
    {
    	// 不能调用非const方法或直接修改成员变量
    	//foo.setBar(1);
    	//foo.baz = 1;
    }
    
    void tryConstFoo(const Foo* foo)
    {
    	// 不能调用非const方法或直接修改成员变量
    	//foo->setBar(1);
    	//foo->baz = 1;
    
    	// const_cast转换为非const指针
    	Foo* casted = const_cast<Foo*>(foo);
    	casted->setBar(1);
    	casted->baz = 1;
    }
    
    int main()
    {
    	// 不修改对象的前提下,可以访问类成员变量和调用const成员函数
    	const Foo foo;
    	std::cout << foo.getBar() << std::endl;
    	std::cout << foo.baz << std::endl;
    
    	// 不能调用非const方法或直接修改成员变量
    	//foo.setBar(1);
    	//foo.baz = 1;
    
    	// const引用
    	tryConstFoo(foo);
    
    	return 0;
    }
    

    Quiz:https://www.geeksforgeeks.org/c-plus-plus-gq/const-keyword-gq/

  12. 友元:声明之后可以访问私有成员和方法

    • 友员也破环了类的隐藏与封装
    • 友元关系不能被继承
    • 友元关系是单向的,不具有交换性
    • 友元关系不具有传递性
    #include <iostream>
    
    class Temperature;
    
    // 友元成员函数所属类的定义必须放在友元声明之前
    class TemperatureTrainee
    {
    public:
    	float queryTemperature(const Temperature& temp);
    	void accessTemperature(const Temperature& temp);
    };
    
    // 演示三种友元的使用方式
    class Temperature
    {
    public:
    	// 传入摄氏度
    	Temperature(float temp)
    	{
    		fTemp = temp * 1.8f + 32.0f;
    	}
    
    	// 返回华氏度
    	float getTemparature() const
    	{
    		return (fTemp - 32.0f) / 1.8f;
    	}
    
    private:
    	// 内部存储为华氏度,不对外暴露
    	float fTemp;
    
    	// 友元函数示例
    	friend void printFahrenheitTemperature(const Temperature& temp);
    
    	// 友元类
    	friend class TemperatureMaster;
    
    	// 友元成员函数
    	friend float TemperatureTrainee::queryTemperature(const Temperature& temp);
    };
    
    // 友元函数可访问Temperature私有成员
    void printFahrenheitTemperature(const Temperature& temp)
    {
    	std::cout << temp.fTemp << std::endl;
    }
    
    // 友元类可访问Temperature私有成员
    class TemperatureMaster
    {
    public:
    	void increateTemperature(Temperature& temp)
    	{
    		temp.fTemp += 1.0f;
    	}
    
    	void decreaseTemperature(Temperature& temp)
    	{
    		temp.fTemp += 1.0f;
    	}
    };
    
    // 友元成员函数可访问Temperature私有成员
    float TemperatureTrainee::queryTemperature(const Temperature& temp)
    {
    	return temp.fTemp;
    }
    
    void TemperatureTrainee::accessTemperature(const Temperature& temp)
    {
    	// 非友元成员函数无法访问
    	//temp.fTemp;
    }
    
    int main()
    {
    	Temperature temp(19.2f);
    	printFahrenheitTemperature(temp);
    
    	TemperatureMaster master;
    	master.increateTemperature(temp);
    
    	return 0;
    }
    

    Quiz:https://www.geeksforgeeks.org/c-plus-plus-gq/friend-function-and-class-gq/

  13. more quiz:https://www.geeksforgeeks.org/c-plus-plus-gq/class-and-object-gq

  14. end

    总体情况

    学习了课上讲的类的相关知识及实用细节,认真体会quiz中的题目,在写task的时候体会了面向对象的编程方法,编码中出现一些问题能够查资料解决。遇到的部分问题:ifstream传参时必须用引用,string类转数字使用stoi函数等等。task完成了数据结构设计与存储,剩余工作为查询部分,同时使用了学习的知识代码复用,简化编码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值