第五集.C++学习

1.指针函数(是一个函数)

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

即定义的时候用指针进行定义,这样表示返回值是一个指针变量,返回一个地址

案例如下:

#include<iostream>
using namespace std;
int  *newInt(int value);
//声明一个指针函数,返回一个地址!!
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;
}

2.函数指针(是一个指针变量)

指向函数首地址的指针变量(存储函数首地址),指向我们可以理解为存储

如:int (*p)()这是一个指向函数的指针变量。

案例如下:

#include <stdio.h>
int fun(int x,int y);
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);/*    int(*p)()也是一样的        */
    p = fun;//给函数指针p赋值,使其指向函数fun,函数名就是首地址!这里存储的相当于函数的地址,然后通过*p调用函数
 
    printf("请输入10个数字:\n");
 
    scanf("%d", &a);
    for(i = 0; i< 9; i++)
    {
        scanf("%d", &b);
        a = (*p)(a,b);//通过指针p调用函数fun,函数正常返回int型
    }
    printf("The Max number is %d.", a);
 
    return 0;
}

3.静态对象强制类型转换

Company是一个基类,TechCompany是一个子类,(两者是继承关系,我们知道可以转换)我们需要将从Company生成的实例,初始化了TechCompany的实例,因此需要通过类型转换强制转换成TechCompany。

如下:

/*静态对象强制类型转换*/
#include <iostream>
using namespace std;
#include <string>
 
class Company
{
public:
    //构造器
    Company(string theName,string product);
    //方法
    virtual void printInfor();//打印信息
 
protected:
    string name;
    string product;
};
//基类构造器实现
Company::Company(string theName,string product)
{
    name = theName;
    this->product = product;
}
//基类方法实现
void Company::printInfor()
{
    cout << "这家公司的名字叫:" << name << "正在生产" << product << endl;
}

class TechCompany:public Company
{
public:
    //构造器
    TechCompany(string theName, string product);
    //方法
    void printInfor();//打印信息
};
//构造器实现
TechCompany::TechCompany(string theName, string product):
            Company(theName, product)
{
}
//方法实现
void TechCompany::printInfor()
{
    cout << name << "公司大量生产了" << product << "\n\n";
}
 
 
int main()
{
    Company *company = new TechCompany("苹果", "IPHONE");
    //将Company类型强制转换为TechCompany类型
    /*不能这样:TechCompany *techCompany = company;因为两个对象不同*/
    TechCompany *techCompany = (TechCompany*)company;
    techCompany->printInfor();
 
//释放内存(此处company与techCompany两个指针都指向TechCompany定义的对象)
//所以释放内存只需要释放一次即可[注意不能停同时删除这两个!!!]
/*不能重复释放啊*/
    delete company;//删除指针地址
    company = NULL;//为指针指向的地址赋空值
    techCompany = NULL;
    return 0;
}

记得删除申请的内存块后,需要把两个指针变量都置为NULL; 

4.动态对象强制类型转换

如果当出现不能转的情况,我们强行转就会出现错误,所以需要采用动态转换,如果转换失败 就会返回NULL,这样我们可以进行条件判断,如果转换失败了,我们就能做到及时止损。

如:这样转很明显是错的。因为两个实例毛关系都没有,转换不过来(开辟的是Company这个类的空间。不是TechCompany)因此需要一个动态转换。

    Company *company = new Company("苹果", "IPHONE");
    TechCompany *techCompany = TechCompany*(company);

正确全体代码如下:

/*动态对象强制类型转换*/
/*万一强制转换的类型和目标类型结构完全不同,这个时候我们就需要采取高级的强制类型转换操作符了!*/
#include <iostream>
using namespace std;
#include <string>
 
class Company
{
public:
    //构造器
    Company(string theName,string product);
    //方法
    virtual void printInfor();//打印信息
 
protected:
    string name;
    string product;
};
//基类构造器实现
Company::Company(string theName,string product)
{
    name = theName;
    this->product = product;
}
//基类方法实现
void Company::printInfor()
{
    cout << "这家公司的名字叫:" << name << "正在生产" << product << endl;
}

class TechCompany:public Company
{
public:
    //构造器
    TechCompany(string theName, string product);
    //方法
    void printInfor();//打印信息
};
//构造器实现
TechCompany::TechCompany(string theName, string product):
            Company(theName, product)
{
}
//方法实现
void TechCompany::printInfor()
{
    cout << name << "公司大量生产了" << product << "\n\n";
}
 
 
int main()
{
    Company *company = new Company("苹果", "IPHONE");
    //Company和TechCompany虽然结构相同,但是属于两个不同对象
    /*先在两个尖括号之间写出想要转换的指针类型,然后将被转换的值写在括号里*/
    TechCompany *techCompany = dynamic_cast<TechCompany*>(company);
    /*如果转换失败就会返回NULL*/
    if(techCompany == NULL)
    {
        cout << "悲催!!!" << endl;
    }
    else
        cout << "成功!!!" << endl;
 
//释放内存(此处company与techCompany两个指针都指向TechCompany定义的对象)
//所以释放内存只需要释放一次即可[注意不能停同时删除这两个!!!]
    delete company;//删除指针地址
    techCompany = NULL;
    company = NULL;//为指针指向的地址赋空值
 
    return 0;
}

5.避免内存泄露

正确的做法:建立一个指针变量,指向整型数组的首地址(1000个整型),然后进行删除释放,并将x置于NULL。+

int *x;
x = new int[1000];
delete[]x;
x = NULL;

错误1: 会导致内存泄露,几个new必须对应几个delete

x = new int[1000];
x = new int[4000];
delete[]x;
x = NULL;

 错误2:函数里面申请空间,出来后会x被消除(指针变量x超过作用域)。那么就只剩下一个申请的地址,但是没有对应的指针了

void foo()
{
    My Class *x;
    x = new MyClass();
}

解决方法

1.设定返回值为这个指针变量,即返回一个地址。

2.在函数里面就进行delete 。

6.容器与算法

能容纳两个或更多值的数据通常我们称之为容器,数组是C++唯一直接支持的容器,但数组并不适合来解决所有的问题。

数组这种数据结构最大的先天不足就是它受限于一个固定的长度。C++标准库提供的向量(vector)类型从根本上解决了数组先天不足的问题(内存固定,如果不用那么多内存编译器也会为其分配),我们用不着对一个向量能容纳多少元素做出限定,因为向量可以动态地随着你往它里面添加元素而无限增大。

  • size()方法查知某给定向量的当前长度(即包含的元素个数);
  • 可以根据访问数组元素的语法来访问给定向量里的各个元素,即下标访问法;
  • push_back()方法往它里面添加东西;
  • begin()方法开始数据的位置;
  • end()方法表示最后元素的下一个位置,不是最后元素的位置。
  • 创建容器的形式:vector<type> vectorName

案例1:容器就像是一个可以不断扩充和收缩的数组

#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main()
{
    vector<string> names;
    names.push_back("刘舸");
    names.push_back("侯悦");
    names.push_back("刘小飞");
    for(int i = 0; i < names.size(); i++)
    {
        cout << names[i] <<endl;
    }
    names[2] = "lg";/*还未添加所以不行*/
    cout << names[2] << endl;

    return 0;
}

案例二:

迭代器(只能指针,这是个指针奥!)

在遍历向量里的各个元素时,我们仍然把其视为C++数组来看待,刚好我们的向量容器允许下标访问names[],但如果改用另一种不提供此方法访问的容器(比如栈),我们就需要做很多修改才能实现。对元素进行遍历是一种十分常见的任务,所以应该有一种标准的方式来做这件事情
iterator(迭代器)就是这么来的是一种复杂指针,可以进行遍历数据。使用迭代器,修改容器时就不需要改很多代码了:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main()
{
    vector<string> names;

    names.push_back("刘舸");
    names.push_back("hy");
    vector<string>::iterator iter = names.begin();/*返回初始位值的值,迭代器是智能指针哦*/

    while(iter != names.end())/*end取最后一个元素的下一个位置,表示底部*/
    {
        cout << *iter << endl;
        ++iter;
    }
    return 0;
}

案例3:算法的魅力

/*C++标准库里也有算法*/
#include<iostream>
#include <string>
#include <vector>//向量
#include <algorithm>//算法
 
int main()
{
    //定义向量
    std::vector<std::string> names;
    //往容器中存放数据
    names.push_back("Larry");
    names.push_back("Rola");
    names.push_back("Dingding");
    names.push_back("Laary");
    names.push_back("TAOM");
    names.push_back("jerry");
    //sort()算法按照英文字母排序
    std::sort(names.begin(), names.end());/*容器里的直接排列*/
    //迭代器;names.begin()开始位置,names.end()表示最后元素的下一个位置
    std::vector<std::string>::iterator iter = names.begin();
    while(iter != names.end())//names.end()表示最后元素的下一个
    {
        //迭代器是智能指针,可以使用*
        std::cout << *iter << "\n";
        ++iter;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值