欢迎加入QQ:498903810 一起交流、讨论知识,里面有大佬,也有小白,天下码农一家亲,大家一起讨论进步。
1、如果类中没有定义这两个函数,编译器会自动添加默认函数;
2、如果使用编译器自动添加的默认函数,默认函数自动调用成员变量的 拷贝构造函数/赋值运算符重载函数 给成员变量 初始化/赋值。(基本类型例如:int、double、char等,没有这两个函数,所以按字节内存拷贝)。
3、如果程序员添加了这两个函数,必须负责全部成员变量的 初始化/赋值,否则,未处理的成员变量按默认行为初始化/赋值(类对象:默认构造,基本类型:随机值)。
1、C++语法返回对象
执行return
语句,拷贝构造返回对象,作为返回值。离开函数调用,局部变量会被析构,但是编译器保留了一份。
2、编译器优化返回对象
多态:不同类型对象调用相同接口完成不同的行为。
1、要有继承
2、要有虚函数重写
3、用父类指针(父类引用)指向子类对象。
注:多态的函数的函数名、函数参数、返回值类型,必须完全相同,但是可以返回本类的指针和引用是可以的。
#include
#include
#include
#include
using namespace std;
class Triangle
{
public:
Triangle (int a, int b, int c):a(a), b(b), c(c){};
virtual int get_area()
{
cout << "我是普通三角形" << endl;
int tmp = (a + b + c) / 2;
return sqrt(tmp * (tmp - a) * (tmp - b) * (tmp - c));
}
protected:
int a;
int b;
int c;
};
class IsoTriangle:public Triangle
{
public:
IsoTriangle(int a = 0, int b = 0):Triangle(a, a, b){}
int get_area()
{
cout << "我是等腰三角形" << endl;
int tmp = (a + a + b) / 2;
return sqrt(tmp * (tmp - a) * (tmp - a) * (tmp - b));
}
private:
};
class RightTriangle:public Triangle
{
public:
RightTriangle(int a = 0, int b =0, int c = 0):Triangle(a, b, c){};
int get_area()
{
cout << "我是直角三角形" << endl;
return a * b / 2;
}
private:
};
int main()
{
Triangle * tmp = NULL, t1(3, 4, 5);
RightTriangle r1(3, 4, 5);
tmp = &t1;
cout << "area = " << tmp->get_area() << endl;//此处发生多态
tmp = &r1;
cout << "area = " << tmp->get_area() << endl;//此处发生多态
cout << "sizeof(tmp) = " << sizeof(tmp) << endl;//64位系统指针 8 个字节
cout << "sizeof(r1) = " << sizeof(r1) << endl;//8 + 12 = 20 ,8字节对齐所以是24
cout << "sizeof(t1) = " << sizeof(t1) << endl;
return 0;
}
运行结果:
我是普通三角形
area = 6
我是直角三角形
area = 6
sizeof(tmp) = 8
sizeof(r1) = 24
sizeof(t1) = 24
一、重写:发生在两个类之间 ————————>重写分为两类:1、虚函数重写发生多态
2、非虚函数 重写(重定义)
二、重载:发生在同一个类中
必须在同一个类中进行
子类无法重载父类的函数,父类同名函数将被名称覆盖
重载是在编译期间根据参数类型和个数决定函数调用
必须发生在父类与子类之间
且父类与子类的函数必须有完全相同的原型
使用
virtual
声明之后能够产生多态(如果不使用,那叫重定义)多态是运行期间根据具体对象的类型决定函数调用
virtual
成员函数会被编译器放入虚函数表中_vptr
指针,当进行虚函数调用时,C++编译器不需要区分子类对象或者父类对象,只需要通过base指针,找到vptr指针即可),_vptr
指针一般作为类对象的第一成员。纯虚函数类—>抽象接口
纯虚函数是一个在基类中说明的虚函数,在基类中没有定义,要求任何派生类都定义自己的版本
纯虚函数未各派生类提供了一公有界面(接口的封装和设计,软件爱你的模块功能划分)
纯虚函数说明形式
virtual 类型 函数名(参数列表) = 0;
一个具有纯虚函数的基类成为抽象类
抽象类不能实例化,且一般不包含成员变量
抽象对象:没有完全实例化的类仍然是一个抽象类,仍然不能实例化。继承抽象类后,本身也可能仍为抽象类。
涉及STL知识如果看不懂,请自行搜索
#include
#include
#include
#include
using namespace std;
//抽象类
class Shape
{
public:
virtual int length() = 0;
virtual ~Shape(){}
};
//三角形
class Triangle: public Shape
{
public:
Triangle(int a = 0, int b =0, int c = 0):a(a), b(b), c(c){}
int length()
{
return a + b + c;
}
private:
int a;
int b;
int c;
};
//等腰三角形
class IsoTriangle:public Triangle
{
public:
IsoTriangle(int a = 0, int b = 0):Triangle(a, a, b){}
private:
};
//直角三角形
class RightTriangle:public Triangle
{
public:
RightTriangle(int a = 0, int b =0, int c = 0):Triangle(a, b, c){};
private:
};
//四边形
class Rect : public Shape
{
public:
Rect(int a = 0, int b =0, int c = 0, int d = 0):a(a), b(b), c(c), d(d){}
int length()
{
return a + b + c + d;
}
private:
int a, b, c, d;
};
int main()
{
vector v1;
Triangle t1(5, 6, 7);
Triangle t2(2, 3, 4);
IsoTriangle t3(4, 6);
IsoTriangle t4(5, 6);
RightTriangle t5(3, 4, 5);
RightTriangle t6(6, 8, 10);
Rect t7(1, 1, 1, 1);
v1.push_back(&t1);
v1.push_back(&t2);
v1.push_back(&t3);
v1.push_back(&t4);
v1.push_back(&t5);
v1.push_back(&t6);
v1.push_back(&t7);
int length = 0;
for(vector ::iterator it = v1.begin(); it != v1.end(); it++)
{
length += (*it)->length();
}
cout << "length = " << length << endl;
}
1、C/C++是如何调用函数的?—>早绑定
void Func()
{
}
int main()
{
Func();
}
call函数地址
2、C++的多态—>迟绑定
虚析构函数:通过父类指针,释放所有的子类资源。
构造函数不能写成虚函数
会出错,内存泄漏
Base *b = new Derive;//不再父类的析构函数前面加virtual会少析构子类
delete b;
#include
using namespace std;
class Base
{
public:
Base()
{
cout << "父类构造函数" << endl;
}
virtual ~Base()//父类虚析构函数
{
cout << "父类析构函数" << endl;
}
};
class Derive:public Base
{
public:
Derive()
{
cout << "子类构造函数" << endl;
}
~Derive()
{
cout << "子类析构函数" << endl;
}
};
int main()
{
//Derive d;
Base *b = new Derive;//不再父类的析构函数前面加virtual会少析构子类
delete b;
return 0;
}