C++入门(5)

欢迎加入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、非虚函数 重写(重定义)

二、重载:发生在同一个类中

重写PK重载

函数重载:

必须在同一个类中进行

子类无法重载父类的函数,父类同名函数将被名称覆盖

重载是在编译期间根据参数类型和个数决定函数调用

函数重写:

必须发生在父类与子类之间

且父类与子类的函数必须有完全相同的原型

使用virtual声明之后能够产生多态(如果不使用,那叫重定义)

多态是运行期间根据具体对象的类型决定函数调用

多态原理探究

原理知识:

  • 当类中声明虚函数时,编译器会在类中生成一个虚函数表
  • 虚函数表是一个储存类成员函数指针的数据结构
  • 虚函数表是由编译器自动生成与维护的
  • virtual成员函数会被编译器放入虚函数表中
  • 当存在虚函数时,每个对象都有一个指向虚函数表的指针,(C++编译器给父类对象,子类对象提前布局_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;
}

你可能感兴趣的:(C++,Linux,C/C++开发工程师之路)