#include <iostream>
#include <cstring>
#define pi 3.14
using namespace std;
class Shape
{
protected:
double round;
double area;
public:
//无参构造
Shape():round(40),area(100){cout<<"Shape::无参构造函数,默认周长为40,面积为100"<<endl;}
//有参构造
Shape(double a,double b):round(a),area(b){cout<<"Shape::有参构造函数"<<endl;}
//析构函数
~Shape(){cout<<"Shape::析构函数"<<endl;}
//拷贝构造
Shape(const Shape &other)
{
this->round=other.round;
this->area=other.area;
cout<<"Shape::拷贝构造函数"<<endl;
}
//拷贝赋值
Shape &operator=(const Shape &other)
{
if(this!=&other)
{
this->round=other.round;
this->area=other.area;
}
cout<<"Shape::拷贝赋值函数"<<endl;
return *this;
}
//移动构造
Shape(Shape &&other)
{
this->round=other.round;
this->area=other.area;
cout<<"Shape::移动构造函数"<<endl;
}
//移动赋值
Shape &operator=(Shape &&other)
{
memcpy(this,&other,sizeof(Shape));
cout<<"Shape::拷贝赋值函数"<<endl;
return *this;
}
};
class Circle:public Shape
{
private:
double radius;
public:
//无参构造
Circle():Shape(2*pi*5,pi*5*5),radius(5){cout<<"Circle::无参构造函数,默认直径为5"<<endl;}
//有参构造
Circle(double c):Shape(2*pi*c,pi*c*c),radius(c){cout<<"Circle::有参构造函数"<<endl;}
//析构函数
~Circle(){cout<<"Circle::析构函数"<<endl;}
//拷贝构造函数
Circle(const Circle &other)
{
this->round=other.round;
this->area=other.area;
cout<<"Circle::拷贝构造函数"<<endl;
}
//拷贝赋值函数
Circle &operator=(const Circle &other)
{
if(this!=&other)
{
this->round=other.round;
this->area=other.area;
}
cout<<"Circle::拷贝赋值函数"<<endl;
return *this;
}
//移动构造
Circle(Circle &&other)
{
memcpy(this,&other,sizeof(Circle));
cout<<"Circle::移动构造函数"<<endl;
}
//移动赋值
Circle &operator=(Circle &&other)
{
memcpy(this,&other,sizeof(Circle));
cout<<"Circle::移动赋值函数"<<endl;
return *this;
}
//获得周长函数
double get_round()
{
return round;
}
//获得面积函数
double get_area()
{
return area;
}
};
class Rect:public Shape
{
private:
double len;
double width;
public:
//无参构造
Rect():Shape(2*5+2*10,5*10),len(5),width(10){cout<<"Rect::无参构造函数,默认长为5,宽为10"<<endl;}
//有参构造
Rect(double a,double b):Shape(2*a+2*b,a*b),len(a),width(b)
{
cout<<"Rect::有参构造函数"<<endl;
}
//析构函数
~Rect(){cout<<"Rect::析构函数"<<endl;}
//拷贝构造函数
Rect(const Rect &other)
{
this->round=other.round;
this->area=other.area;
cout<<"Rect::拷贝构造函数"<<endl;
}
//拷贝赋值函数
Rect &operator=(const Rect &other)
{
if(this!=&other)
{
this->round=other.round;
this->area=other.area;
}
cout<<"Rect::拷贝赋值函数"<<endl;
return *this;
}
Rect(Rect &&other)
{
memcpy(this,&other,sizeof(Rect));
cout<<"Circle::移动构造函数"<<endl;
}
//移动赋值
Rect &operator=(Rect &&other)
{
memcpy(this,&other,sizeof(Rect));
cout<<"Circle::移动赋值函数"<<endl;
return *this;
}
//获得周长函数
double get_round()
{
return round;
}
//获得面积函数
double get_area()
{
return area;
}
};
int main()
{
Circle a;
cout<<"获得a面积为"<<a.get_area()<<endl;
cout<<"获得a周长为"<<a.get_round()<<endl;
Rect b;
cout<<"获得b面积为"<<b.get_area()<<endl;
cout<<"获得b周长为"<<b.get_round()<<endl;
Circle c(3);
cout<<"获得c面积为"<<c.get_area()<<endl;
cout<<"获得c周长为"<<c.get_round()<<endl;
c=a;
cout<<"获得c面积为"<<c.get_area()<<endl;
cout<<"获得c周长为"<<c.get_round()<<endl;
Rect d=b;
cout<<"获得d面积为"<<d.get_area()<<endl;
cout<<"获得d周长为"<<d.get_round()<<endl;
Rect e=move(d);
cout<<"获得e面积为"<<e.get_area()<<endl;
cout<<"获得e周长为"<<e.get_round()<<endl;
return 0;
}
运行结果:
9.12面试题
1、面向对象的三大特征
三大特征分别为封装、继承、多态(为讲,后面补充)
封装就是把一个事物对象的一些行为和属性都封装起来,而封装具有public、protected、private三种权限,可以起到对属性和一些函数的保护;
继承,就是在一个类的基础上去定义另一个新类的过程叫做继承,继承的方式有三种,分别是public、protected、private,而这三种方式会改变父类的权限,也可以用using改变权限,继承的本质其实相当于在子类的最前面构造了一个父类,从而达到全盘吸收,在此基础上子类也可以拓展新成员。
2、谈谈C++中的友元
友元就是给对面开权限,允许对面来访问自己类的所有权限成员,包括私有成员。
友元分为友元函数和友元类,普通的类的非成员函数是无法访问受保护成员和私有成员的,但是设置成友元后都可以访问,友元可以将友元函数和其他类成员设置为友元。
友元是单向的,A将B设置为友元表示A向B给权限,而A不一定有权限访问B;
友元不具有传递性,A是B的友元,B是C的友元,但A不一定是C的友元;
友元不具有继承性,父类是友元,子类不一定是友元;
友元破坏了封装性,因为其破坏了权限对访问的限制,因此尽可能少使用友元;
在提取和插入运算符重载时,需要使用全局函数作为友元函数;
3、什么是命名空间,为什么要使用命名空间?
命名空间是为一个内部区域标识符的集合,命名空间不仅可以解决多人协同开发时名字污染问题,还可以给不同的名字加上一个姓氏,这样可以明确的找到某个功能或者函数;嵌套定义的命名空间需要一级一级挨个往下使用,而重名且作用域相同的命名空间可以合并,因此他们之间不能有重名。
4、C++中的类提供的特殊成员函数有哪些?
特殊成员函数有无参构造、析构函数、拷贝构造、拷贝赋值、移动构造、移动赋值。
无参构造是系统自动分配的,构造类都可以在括号后面跟上初始化列表,当显性定义了有参构造后,系统提供的无参构造就不见了;拷贝构造和拷贝赋值也是系统有提供的,但是这种拷贝是浅拷贝,只是对成员变量进行简单的赋值,如果类中没有指针类型是没问题的,但当类中有指针类型且指向堆区空间,浅拷贝只会将指针的指向简单赋值,因此两个指针指向同一块堆区空间,使用时会造成竞态问题,释放时会出现多次释放的段错误;移动构造和移动赋值是对拷贝构造和拷贝赋值的补充,所引用的是右值,不需要定义出类对象就可以对类对象进行赋值和构造;析构函数系统也会提供,在系统提供的析构函数只会对类空间进行释放,因此如果类成员中有指向堆区空间的时候,需要显性定义析构函数,来完成对堆区空间的释放,防止内存泄漏。
5、C++的静态成员函数和静态成员变量?
首先,静态成员创造出来是为了让其脱离类对象本身,在静态区分配空间;多个类对象对应一个静态成员,对应一块空间,相当于是类对象中的全局变量,但更能体现类的封装性;改变静态成员,其他类对象中的静态成员也会改变;在定义成员变量前加上static就可以编程静态成员变量;静态成员变量需要在类内声明,类外定义,不初始化默认为0;
静态成员函数是在函数前加static,相当于定义了一个全局函数,只有对该类和类对象进行调用;可以通过类对象调用成员运算符或者类名直接调用;在静态成员函数中没有this指针;不依赖于类对象,也可以不实例化对象,直接使用类名进行调用;在静态成员函数中只能使用静态成员变量。
6、C++中的深浅拷贝问题?
首先,深浅拷贝问题是在拷贝构造和拷贝赋值这两个特殊成员函数中出现的,当使用系统给的拷贝构造和拷贝赋值时,只是对类成员的简单赋值,即浅拷贝;如果类中没有指针类型时,浅拷贝是没有问题的,但如果有,则会导致两个指针指向同一块空间;所以需要深拷贝,拷贝的指针需要重新在堆区申请一块空间,然后再把空间中的内容进行赋值。
思维导图:day4补充:有道云笔记 day5:有道云笔记