小甲鱼C++快速入门——第七天

视频33——动态内存分配

静态内存

在完成它的任务时所使用的内存空间都是固定不变的,不能在程序运行期间动态增加或减少内存空间

动态内存

动态内存由一些没有名字、只有地址的内存块构成,那些内存块是在程序运行期间【和静态内存的主要区别】动态分配的。他们来自一个由标准C++库替你管理的大池子(术语“内存池”),从内存池申请一些内存需要用到new语句,它将根据你提供的数据类型分配一块大小适当的内存。

在使用动态内存时,最重要的原则是每一条new语句都必须有一条与之配对的delete语句,否则将导致内存泄漏。

delete语句只释放给定指针变量正指向的内存块,不影响这个指针。在执行delete语句之后,那个内存块被释放了,但指针变量还依然存在。所以一般保险起见需要设置i = NULL

#include <iostream>
using namespace std;
#include <string>

基类
class Company
{
public:
    //构造器
    Company(string theName);
    //方法
    virtual void printInfor();//打印信息

protected:
    string name;
};
//基类构造器实现
Company::Company(string theName)
{
    name = theName;
}
//基类方法实现
void Company::printInfor()
{
    cout << "这家公司的名字叫:" << name << endl;
}
子类
class TechCompany:public Company
{
public:
    //构造器
    TechCompany(string theName, string product);
    //方法
    void printInfor();//打印信息
private:
    string product;
};
//构造器实现
TechCompany::TechCompany(string theName, string product):
            Company(theName)
{
    this->product = product;
}
//方法实现
void TechCompany::printInfor()
{
    cout << name << "公司生产了" << product << "\n\n";
}


int main()
{
    Company *company = new Company("苹果");
    company->printInfor();

    delete company;//删除指针地址
    company = NULL;//为指针指向的地址赋空值

    company = new TechCompany("APPLE", "IPHONE");
    company->printInfor();
    delete company;//删除指针地址

    return 0;
}

视频34——动态数组

虽然前面讲过的用new给基本类型和对象在运行时分配内存,但它们的尺寸在编译时就已经确定下来——因为我们为之申请内存的数据类型在程序中有明确的定义,有明确的单位长度;但有些时候,必须等到程序运行时才能确定需要申请多少内存,甚至还需要根据程序的运行情况追加申请更多的内存。例如:  int *x = new int[10];//x表示整型数组的数组名

删除动态数组

#include <iostream>
#include <string>
using namespace std;

int main()
{
    unsigned int count = 0;

    cout << "请输入数组的元素个数:" << '\n';
    cin >> count;
    //程序运行时才申请,不是在编译的时候,所以叫做动态的
    //在堆里面申请,不是在栈【一般局部变量在栈中申请】里申请 。
    int *x = new int[count];
    //数组赋值
    for(int i = 0; i< count; i++)
    {
        x[i] = i;
    }
    //输出打印
    for(int i = 0; i< count; i++)
    {
        cout << "x[" << i << "] = " << x[i] << endl;
    }

    return 0;
}

PS:(1)动态数组:程序运行时才申请,不是在编译的时候,所以叫做动态的;在堆里面申请,不是在栈【一般局部变量在栈中申请】里申请 。

视频35——从函数或方法返回内存

基本思路:在函数里调用new语句为某种对象或某种基本数据类型分配一块内存,再把那块内存的地址返回给程序的主代码,主代码将使用那块内存并在完成有关操作后立刻释放delete

#include <iostream>
using namespace std;

int *newInt(int value)
{
    int *myInt = new int;
    *myInt = value;

    return myInt;
}

int main()
{
    int *x = newInt(20);
    cout << *x;

    delete x;
    x = NULL;

    return 0;
}
#include <iostream>
using namespace std;

void swap(int *x,int *y)
{
//永远不会被执行;想要执行的话把0换为1
#if 0
    int temp;
    temp = *x;
    *x = *y;
    *y = temp;
#endif
    //^异或运算符
    *x ^= *y;
    *y ^= *x;
    *x ^= *y;
}

int main()
{
    int a,b;
    a = 3;
    b = 5;

    swap(&a,&b);

    cout << "a = " << a
         << ", b = " << b << endl;

    return 0;
}

PS:“#if 0 ……………………#endif”语句功能和“/*……………………*/”一样。

函数指针&指针函数

函数指针:指向函数首地址的指针变量称为函数指针。

指针函数:一个函数可以带回一个整型数据的值,字符类型值和实型类型的值,还可以带回指针类型的数据,使其指向某个地址单元。

/**< 函数指针 */
#include <stdio.h>

int fun(int x,int y)
{
    int z;

    z = (x > y)? x:y;
    return z;
}

int main()
{
    int i,a,b;
    //声明函数指针
    //函数如何声明参数【类型、个数】那么函数指针就应该如何声明参数,否则会出错。
    int (*p)(int,int);
    p = fun;//给函数指针p赋值,使其指向函数fun

    printf("请输入10个数字:\n");

    scanf("%d", &a);
    for(i = 0; i< 9; i++)
    {
        scanf("%d", &b);
        a = (*p)(a,b);//通过指针p调用指针函数fun
    }
    printf("The Max number is %d.", a);

    return 0;
}

PS:函数指针的参数变量如何声明取决于相应函数参数变量如何声明,包括参数变量的类型和个数。eg:上述程序中函数声明为int fun(int x,int y);那么其函数指针声明为int (*p)(int,int);不可以是int (*p)();

/**< 指针函数 */
#include<iostrem>
using namespace std;

//声明一个指针函数,返回一个地址
int  *newInt(int value)
{
    int *myInt = new int;
    *myInt = value;
    
    return myInt;
}


int main()
{
    //新建一个整型变量空间,并将x指针指向这个空间
    int  *x = newInt(20);
    
    cout << *x;
    delete x;
    x = NULL;

    return 0;
}

视频36——副本构造器

我们可以把一个对象赋值给一个类型与之相同的变量,编译器将生成必要的代码把“源”对象各属性的值分别赋值给“目标”对象的对应成员。这种赋值行为称之为逐位复制。(但如果某些成员变量是指针的话,对象成员逐位复制的结果是你将拥有两个一模一样的实例,而这两个副本里的同名指针会指向相同的地址

/**< 带指针变量的等号重载 */
#include <iostream>
using namespace std;

class MyClass
{
public:
    //构造器
    MyClass(int *p);
    //析构器
    ~MyClass();

    //运算符“="重载
    MyClass &operator = (const MyClass &rhs);
    void print();

private:
    int *ptr;
};
//构造器实现
MyClass::MyClass(int *p)
{
    ptr = p;
}
//析构器实现
MyClass::~MyClass()
{
    delete ptr;
}
//运算符(=)重载实现,rhs为另一对象
MyClass &MyClass::operator=(const MyClass &rhs)
{//obj1不等于obj2时,this指针指的是指向当前类生成的对象(此处指第一个MyClass)
    if(this != &rhs)
    {
        delete ptr;//删除地址ptr,释放obj1的内存

        ptr = new int;//创建新的内存给指针ptr
        *ptr = *rhs.ptr;//解引用,将obj2的值赋值给obj1
    }
    else
    {
        cout << "赋值号两边为同个对象,不做处理!\n";//obj1 = obj2时
    }
    return *this;//返回第一个MyClass对象
}
void MyClass::print()
{
    cout << *ptr << endl;
}

int main()
{
    MyClass obj1(new int(1));//创建对象obj1
    MyClass obj2(new int(2));//创建对象obj2

    obj1.print();//打印对象obj1中指针指向的地址的储存值
    obj2.print();//打印对象obj2中指针指向的地址的储存值

    obj2 = obj1;//obj1通过等号重载给obj2

    obj1.print();//打印对象obj1中指针指向的地址的储存值
    obj2.print();//打印对象obj2中指针指向的地址的储存值

    return 0;
}
/**< 副本构造器 */
#include <iostream>
using namespace std;

class MyClass
{
public:
    //主构造器【不需要返回类型】
    MyClass(int *p);
    //副本构造器
    MyClass(const MyClass &rhs);
    //析构器
    ~MyClass();

    //运算符(=)重载,对象复制,括号里声明对象调用副本构造器
    MyClass &operator = (const MyClass &rhs);
    void print();

private:
    int *ptr;
};
//主构造器实现
MyClass::MyClass(int *p)
{
    cout << "进入主构造器\n";
    ptr = p;
    cout << "离开主构造器\n";
}
//副本构造器实现
MyClass::MyClass(const MyClass &rhs)
{
    cout << "进入副本构造器\n";
    *this = rhs; //等号赋值重载
    cout << "离开副本构造器\n";
}
//析构器实现
MyClass::~MyClass()
{
    cout << "进入析构器\n";
    delete ptr;
    cout << "离开析构器\n";
}
//运算符(=)重载实现,rhs为另一对象
MyClass &MyClass::operator=(const MyClass &rhs)
{
    cout << "进入赋值语句重载\n";
    //obj1不等于obj2时,this指针指的是指向当前类生成的对象(此处指第一个MyClass)
    if(this != &rhs)
    {
        delete ptr;//删除地址ptr,释放obj1的内存

        ptr = new int;//创建新的内存给指针ptr
        *ptr = *rhs.ptr;//解引用,将obj2的值赋值给obj1
    }
    else//obj1与obj2为同一个对象时
    {
        cout << "赋值号两边为同个对象,不做处理!\n";//obj1 = obj2时
    }
    cout << "离开赋值语句重载\n";
    return *this;//返回第一个MyClass对象
}
void MyClass::print()
{
    cout << *ptr << endl;
}

int main()
{
    MyClass obj1(new int(1));//创建对象obj1
    MyClass obj2(new int(2));//创建对象obj2
    obj2 = obj1;//obj1通过等号重载给obj2
    obj1.print();//打印对象obj1中指针指向的地址的储存值
    obj2.print();//打印对象obj2中指针指向的地址的储存值
    cout << "---------------------------------------------\n";


    MyClass obj3(new int(3));//创建对象obj3
    MyClass obj4 = obj3;
    obj3.print();//打印对象obj3中指针指向的地址的储存值
    obj4.print();//打印对象obj4中指针指向的地址的储存值
    cout << "---------------------------------------------\n";

    MyClass obj5(new int(5));//创建对象obj5
    obj5 = obj5;
    obj5.print();//打印对象obj5中指针指向的地址的储存值
    cout << "---------------------------------------------\n";

    return 0;
}

程序运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值