C++学习笔记2,面试常问(适合有基础)

12.访问权限

公共权限:public 类内可以访问,类外可以访问
保护权限:protected 类内可以访问,类外不可以访问
私有权限:private 类内可以访问,类外不可以访问

13.struct和class的区别

struct和class的唯一区别在于默认的访问权限不同
struct的默认访问权限为公共
class的默认访问权限为私有

14.构造函数和析构函数

如果不提供构造函数和析构函数,编译器会提供,但是空实现
都是编译器自动调用
构造函数:类名(){},可以重载,创建对象时,会自动调用构造函数
析构函数:~类名(){},不可以有参数,因此无法重载,程序在对象销毁前会自动调用析构

15.构造函数的调用和分类

(1)分类
按参数分类:无参构造,有参构造
按类型分类:普通构造和拷贝构造

class Person{
public:
	Person()
	{
		cout<<"Person的无参构造函数"<<endl;
	}
	Person(int age)
	{
		this->age=age;
		cout<<"Person的有参构造函数"<<endl;
	}
	Person(const Person& p)
	{
		this->age=p->age;
		cout<<"Person的拷贝构造函数"<<endl;
	}
	~Person()
	{
		cout<<"Person的析构函数"<<endl;
	}
private:
	int age;
};
		

(2)调用
括号法:

Person p;//无参(默认)构造函数调用
//注意不能写成Person p();编译器会认为这是一个函数声明
Person p2(10);//有参构造函数调用
Person p3(p2);//拷贝构造函数调用

显示法:

Person p;//默认构造函数调用
Person p2=Person(10);//有参构造函数调用
Person p3=Person(p2);//拷贝构造函数调用

Person(10);//匿名对象,当前行结束后,系统会立即回收匿名对象
Person(p3);//会发生错误,因为Person(p3)等价于Person p3,
//会导致重定义,所以不要用拷贝构造函数初始化匿名对象

隐式法:

Person p;//默认构造函数调用
Person p2=10;//有参构造函数调用,相当于Person p2=Person(10);
Person p3=p2;//拷贝构造函数调用,相当于Person p3=Person(p2);

16.拷贝构造函数的调用时机

(1)使用一个创建完毕的对象来初始化一个对象

Person p(10);
Person p2(p);//会调用拷贝构造函数

(2)值传递的方式给函数参数传值

void func(Person p){}
void func2(Person &p){}
int main(){
	Person p;
	func(p);//值传递会调用拷贝构造函数
	func2(p);//采用引用不会调用拷贝构造函数,特别是当数据量大的时候可以节省性能
}

(3)值方式返回局部对象

Person func(){...}
Person& func2(){...}
int main(){
	Person p=func();//会调用拷贝构造函数
	Person& p2=func2();//不会调用拷贝构造函数
}

17.深拷贝与浅拷贝

浅拷贝:简单的赋值拷贝操作
深拷贝:在堆区重新申请空间,进行拷贝操作
浅拷贝带来的问题就是堆区内存重复释放

class Person(){
private:
	int age;
	int* height;
public:
	Person(){}
	Person(int age,int height){
		this->age=age;
		this->height=new int(height);
	}
	Person(const Person& p){//浅拷贝,简单的值拷贝
		this->age=p.age;
		this->height=p.height;
	}
	~Person(){
		if(height!=NULL){
			delete height;
			heigth=NULL;
		}
	}
};
int main(){
	Person p(10,180);
	Person p2(p);
	cout<<p.age<<" "<<*(p.height)<<endl;
	cout<<p2.age<<" "<<*(p2.height)<<endl;
}

上面的代码会出问题,原因是:

Person p(10,180);//调用有参构造
Person p2(p);//调用拷贝构造
//输出数据
//调用析构函数,p的height不为NULL,释放height所指区域
//调用析构函数,(注意p的height为空,但p2的height不为空,
//仍保存着之前height所指向地方的地址),再次执行delete
//但由于之前的内存已被释放,导致堆区内存重复释放
//将拷贝构造函数修改如下
Person(const Person& p){
	this->age=p.age;
	//做深拷贝,拷贝数据,而不是单纯拷贝地址
	this->height=new int(*p.height);
}

总结:如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题,此外,重在赋值运算符时也要注意浅拷贝带来的堆区内存重复释放的问题

18.初始化列表

构造函数():属性名1(值1),属性名2(值2)…{}

class Person{
public:
	Person():m_age(1),m_name("张三"){}
	Person(int age,string name):m_age(1),m_name("李四"){}
	int m_age;
	string m_name;
};

19.类对象作为类成员

C++类中的成员可以是另一个类的对象,我们称该成员为对象成员
构造的时候先构造其他类对象,再构造本类对象
析构的时候先析构本类对象,再析构其他类对象

#include<iostream>
using namespace std;
class A{
public:
	A(){
		cout<<"A的构造函数调用"<<endl;
	}
	~A(){
		cout<<"A的析构函数调用"<<endl;
	}
};
class B{
public:
	B(){
		cout<<"B的构造函数调用"<<endl;
	}
	~B(){
		cout<<"B的析构函数调用"<<endl;
	}
	A a;
};
int main(){
	B b;
}

结果为:

A的构造函数调用
B的构造函数调用
B的析构函数调用
A的析构函数调用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值