类与对象-

1,第一遍:知道。直接看答案,不要自己想,了解所有最优解,方法技巧第一。做题套路,以印象为主。建立一个较为完整的刷题思维体系。
2,第二遍:熟悉。过easy题,记住;做medium,重点题背,反复背。最简单会,大多不会。记住做题套路,以记住为主。
3,第三遍:做题。做easy题;做部分medium题,hard题有思路。夯实medium基础。熟练运用做题套路,以做题为主。
4,面经:做面经,开阔思路,了解出题形式。基础决定上层建筑,基础牢轻松,不牢就痛苦
开发:2个困难,测开:各1个困难 中等
C语言和C++的区别与联系:添加链接描述
添加链接描述
C 可以做应用程序吗1、当然可以,理论上讲C可以完成所有的工作,但是考虑到实际工作量C只能做一部分软件。C主要是用在嵌入式中,一些对性能要求较高的系统软件的底层也用C来做。C++是面向对象的语言,在开发大型的软件中在结构上比C更清晰。两个语言都可以开发软件,只是侧重点不太一样。
2、C作为编程语言,它最主要的用途是在硬件方面,做一些嵌入式的直接对应硬件的控制软件,很少用于开发系统软件。而且系统软件是十分复杂与大型的软件,不可能由哪一种编程语言独立开发,特别是现在的系统越来越复杂与繁琐。

模板

template<class T1,class T2> 
template<typename T1, typename T2>
template<class T1,typename T2>.

类:描述对象有那些属性,有那些方法(函数),对象:类的具体的体现。
封装:数据+方法

缺省参数

#include <iostream>
using namespace std;
void TestFunc(int a = 10, int b = 20, int c = 30)
cout << "a = " << a << endl;
cout << "b =<< b << endl ;
cout<< "c = " << c << endl; 
	//对于全缺省具有多种调用方式
int main(){
	TestFunc(); // 可以全部都缺省,结果= 10 20 30
	printf("\n");
	TestFunc(1);//缺省2个,结果= 1 20 30
	printf("\n") ;
	TestFunc(12) ://缺省1个,结果= 1 2 30
		printf("\n") ;
		TestFunc(123);//都不缺省,结果= 1 2 3
}

必须从左往右缺省

#include <iostream>
using namespace std;
void TestFunc(int a, int b = 20, int c = 30)
cout << "a = " << a << endl;
cout << "b =<< b << endl ;
cout<< "c = " << c << endl; 
	//对于半缺省具有多种调用方式
int main(){
	TestFunc(1);//缺省2个,对于没有默认值的就必须传,结果= 1 20 30
	printf("\n") ;
	TestFunc(12) ://缺省1个,结果= 1 2 30
		printf("\n") ;
		TestFunc(123);//都不缺省,结果= 1 2 3
}

引用

C++中,自定义类型对象传参,尽量不要使用传值传参(拷贝构造),尽量使用引用传参,这样可以减少一次拷贝构造。
对于常量使用的是const修饰,在引用的时候也一定要加const

const int& ra=NULL;//空值NUILL不能引用,这样做没有意义

inline

使用内联函数以后,就不在消耗指针去调用函数,而是直接遇见就展开,当有循环或者递归的时候不适用inline,消耗的空间太大。

class A1 { 
public:    
	void f1(){} 
private:    
	int _a; 
};//sizeof(A1) : 4

class A2 
{ 
public:   
	void f2() {}// sizeof(A2) :1
};

构造函数

类名(形参参数)//构造函数的声明/原型
类名(类名& 对象名)//拷贝构造函数的声明/原型

class Date{
public:
void Init(int year,int month,int day){
_year = year;
_month = month;
_day = day ;
}
void Print (){
cout<<_year <<"-"<<_month << "-"<<_day << endl;
}
private :
int _year;
int _month;
int _day;
};
int main(){
Date d1;
d1.Print();
Date d2;
d2.Init(202126);
d2.Print() ;
return 0;}

结果:一858993460——858993460——858993460(随机值)
2021-2-6.
无参构造函数和有参构造函数不能同时存在,不然调用会存在歧义,如果写了1个全缺省的构造函数同时还存在一个无参的构造函数, 此时你是调用的全缺省函数还是调用的无参的构造函数呢?更好的写法:直接给一个全缺省的构造函数,既可以使用无参的情况,也可以使用有参的情况
有的类没有拷贝构造的函数,每个类能有多个构造函数。
类的构造函数如果都不是public访问属性,通过静态方法,类的实例可以创建:

class Test{
public:
	static Test* GetInst(){//静态方法,应用场景:单例模式
		return new Test;
	}
private:
	Test(){
		cout << "Test::Test ()" << endl;
	}
};
void main(){
	Test *pt = Test:: GetInst();
}//结果:Test::Test ()

赋值、初始化的区别:
赋值操作中调用了重载“=”的函数,初始化中的“=”调用的是默认的构造函数,
构造函数:调用的时候好似通过参数传进来的那个对象来初始化一个对象,赋值函数就是一个已经初始化的对象来进行operator=操作;
拷贝构造是特殊的构造函数,3种应用场景:

1:A a1;
A a2(a1);用一个对象去初始化同一个类的另一个新对象
传参时调用拷贝构造函数,函数的形参对象,调用函数进行形参和实参结合时:
2:void fun(A a)
{}
函数的返回值是类的对象,函数执行返回调用时:
3:A fun()
{a是临时变量,函数结束后,返回的不是a,是a的一份拷贝
A a;return a;
}

以下代码共调用7次拷贝构造函数:

widget f(widget u){F(x)1次:传参到u;5次:用w构造临时对象,用于返回值
widget v(u) ;用u拷贝构造v
widget w=v;用已有的对象v拷贝构造新对象w,不是赋值
return w;用w构造临时对象,用于返回值
}

main(){
widget x;
widget y=f(f(x) ) ;
}

在这里插入图片描述
当函数返回值是类类型对象时,编译器可能会对返回值类型进行优化:9次改为7次
题目:A为一个类,执行下面语句,会自动调用该类构造函数6次

A a[5],*b[3]c(3),*d,
A *e=new A
A &f=c;//引用
b:指针数组,每个元素都是一个A*类型指针,放地址,指向A类型的3个连续的空间,没有创建对象
a:5个A对象的一个数组,调用5次A类的构造函数
c:创建对象
e:在堆上创建对象

析构函数

日期类的析构函数是没有用的,没有任何需要清理的资源,系统所默认生成的就可以用
对于栈来说,需要析构函数清理资源:

class Stack{
public:
	Stack(int capacity = 4){
		_a = (int*)ma11oc(sizeof(int)*capacity);
		_size = 0;
		__capacity = capacity;
	}
	~Stack(){
		free(_a);
		 _a = nul1ptr;
		_size = _capacity = 0;}

对象里面存的是成员变量,成员函数的地址没有存在对象中;不同文件,多个全局对象,谁先析构是不确定的
题目:A类只能通过new来创建(即如果直接创建对象,编译器将报错),应该:将析构函数(可以定义在类外)设为私有
然后,再给A类增加一个公有的方法:

void Release(A*& p){
delete p;}

否则,没法析构,会内存泄露。

~A{
delete this;不能在析构函数中delete this,形成了无限递归,程序运行时候会栈溢出而导致程序崩溃
}

释放对象中资源,但并不是所有的对象都是从堆上new出来的,so不一定用delete,
this指针的指向不能被修改
const对象只能调用const类型成员函数构造函数和析构函数都可以是虚函数

运算符重载

运算符重载:为了让自定义类型可以像内置类型一样去用运算符,增强程序的可读性。每个运算符具体如何实现,是根据类型的意义来定的,并且一个并不是每个运算符都有重载,有意义才重载,日期+日期=无意义,日期*日期=无意义=不重载,日期+天数=有意义=重载;运算符重载可以重载为全局;一般情况下,运算符重载成全局的函数,不好访问成员变量,不好实现,所以一般情况下,都是实现成成员函数。双目运算符的:有2个参数;
运算符重载2种方式:1.重载成类的成员函数—形参数目看起来比该运算符需要的参数个数少1,成员函数有隐藏的this;2.重载成类的友元函数----必须有一个参数要是类类型的对象。
重载前缀1元运算符为成员函数时,其参数表中没有任何参数,Date& operator++():前缀,后缀:Date operator++(int)。
初始化和赋值的不同含义是拷贝构造函数调用的原因。事实上,拷贝构造函数是由普通构造函数和赋值操作符共同实现的
赋值运算符只能作为类的成员函数重载

const

const void print();//返回值是const
void const print();
void print() const;//const成员函数=常成员函数=常函数,const对象只能调用const类型成员函数
void print(const);//参数是const
const A& a;//a不能被修改,A是类

static

class A{
private :
const static int a = 10;类内初始化
static int b;声明
};
int A:: b=20;类外初始化,定义,用类名调用

初始化列表

#include<iostream>
#include <string>
using namespace std;
class Time
{
public:
	Time(int hour = 0, int second = 0)//构造函数
		:_hour(hour)
		, _second(second)
	{
		cout << "Time(int hour = 0, int second = 0)" << endl;
	}

	Time& operator=(const Time& t)//赋值
	{
		cout << "Time& operator=(const Time& t)" << endl;
		return *this;
	}

private:
	int _hour;
	int _second;
};
//方法1:不用初始化列表时:
class Date
{
public:
		Date(int year, int month, int day, int hour, int second)
			{
		_year = year;
		_month = month;
		_day = day;
		Time t(hour, second);//构造对象
		_t = t;//对象赋值给_t
	}
//方法2:用初始化列表时:
	/*public:
		Date(int year, int month, int day, int hour, int second)
		:_t(hour, second)
			{
		_year = year;
		_month = month;
		_day = day;
			}*/
private:
	int _year; // 声明
	int _month;
	int _day;
	time _t;
};

int main()
{	date d(2020, 1, 1, 1, 1);//d:对象;变量进行私有化,函数进行公有
	return 0;}

在这里插入图片描述
在这里插入图片描述
类中包含以下成员,必须在定义时进行初始化:
自定义类型成员(该类没有默认构造函数)

class time
{
public:
	time(int hour = 0)//方法1
		:_hour(hour)
	{
		cout << "~hour()" << endl;//结果:打印出了~hour()
	}
private:
	int _hour;
};
class Date
{//this指针类型:Date *const this
public:
	Date(int year)
	{
		_year = year;
	}
private:
	int _year;
	time _t;
};
int main()
{
	Date d1(2021);
	return 0;
}

class A {
public:
	A(int a)//方法2:没有默认构造函数(默认成员函数)时
		:_a(a)
	{}
private:
	int _a;
};
class B {
public:
	B(int a)
		:_aobj(a)
			{}
private:
	A _aobj; // 没有默认构造函数
	};

part1:

class Solution {
public:
	int StrToInt(string str) {
		int n = str.size();
	//……
	}}
class string
{
  string(const char* str)
  {}
private:
	// ...
};
int main()
{	string str("1234");
	cout << Solution().StrToInt(str) << endl;//方法1
	cout << Solution().StrToInt(string("1234")) << endl;//方法2 匿名对象
	cout << Solution().StrToInt("1234") << endl;//方法3,那这里其实就是隐式类型,转换+优化-》直接调用函数的结果
return 0;}

new/delete对比malloc/free

1、用法的区别2、是否调用构造函数和析构函数问
C语言处理错误的方式一般是返回错误码,所以malloc失败返回0
C++处理错误的方式一般抛异常,所以operator new和new失败抛昇常
new等价于 operator new +构造函数
operator new等价于 malloc + malloc失败抛异常
delete等价于 析构函数+ operator delete
operator delete 等价于 free
申请空间的是虚拟内存,通过共享映射到达物理内存,

模拟实现底层不是为了用其,而是为了明白到达是什么,
走在城市路的司机只用会开车即可,到藏区、无人区的司机(程序员)需要知道发动机(底层)的基础知识,大致知道哪里出问题,如何修。至少拿2个靠谱的offer,去大公司:不易被裁,去好部门:年终奖;

链表的节点ListNode通过重载类专属 operator new/ operator delete,实现链表节点使用内存池申请和释放内存,提高效率。频繁的申请和释放结点,这个过程会不停的和系统打交道,且产生内存碎片的问题,问题很大且效率也会很低;专属重载以后,系统直接给1块内存的位置,想要申请空间,就到里面去找地方开空间=内存池,系统不要一直管你的事情了,系统来说进程实在太多。这样以后new不再调用全局的operator new,而是取调用你专属重载的operator new。

迭代器

原生指针就是天然的迭代器,迭代器时像指针一样的类型,但是不一定是指针。auto的原理就是根据后面的值,来自己推测前面的类型是什么。auto的作用就是为了简化变量初始化,如果这个变量有一个很长很长的初始化类型,就可以用auto代替。

std::vector<std::string> ve;
std::vector<std::string>::iterator it = ve.begin();
 我们可以用atuo来代替那个初始化类型:
auto it = ve.begin();

c_str()

int main()
{string s("hello");
	s.push_back('\0');
	s.push_back('x');
	s.push_back('x');
	s.push_back('x');
	for (auto e: s)
	{
		cout << e << " ";
	}
	cout << endl;//结果:h e l l o X X X
	cout << s.c_str() << endl;//hello,见‘\0’就相当于到头
	cout << s << endl;//hello XXX,不遇见最后的‘\0’是不会停止的
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值