C++笔记(4)

1.通过引用的一些了解,得到以下结论:
   结论一:
   引用必须初始化;初始化的值一定是能取地址的。
int main(int argc,char *argv[])
{
    int &b=a;//&必须和变量名连接,此处是引用初始化
    int *&p2=(int *)0x100;// xx 指针的引用,0x100是常量,不能取地址
}
   结论二:
   普通的引用变量不能引用常量;如果要引用,必须得用常引用才能引用常量(因为对立即数产生了临时量)
//int &a=20;//xx普通的引用变量引用了常量
const int &a=20;
/*
    const int temp = 20;
    const int &a = temp;
*/

//int *&p2=(int *)0x100;//xx普通的指针引用常量引用了指针常量
int *const &p2=(int *)0x100;
/*
    int *const ptemp = (int*)0x100;
    int *const &p2 = ptemp;
*/

   结论三:
   常引用和const指针才能引用或指向常量。
const int a=10;//常量
int &b=a;//false-->const int &b=a;//true 常引用
int *p=&a;//false-->const int *p=&a;//true const指针
2.补充类型转换问题:
int a=10;
int *p=&a;
const int *&q=p;
       ||
const int **q=&p;//const int **     int **//false

int a=10;
const int *p=a;
int *&q=p;
    ||
int **q=&p;//int **      const int **//false
3.C/C++中的动态内存开辟:
   C:malloc/free;
   (1)malloc和free是函数(libc.so C语言的库函数)
int *p1=(int *)malloc(sizeof(int));//(int *)对(void *)进行强转
free(p1);
   (2)free释放内存的时候,不区分释放的是单个元素内存还是数组内存
int **p2=(int **)malloc(sizeof(int *)*3);//存放3个整型指针
for(int i=0;i<3;++i)
{
    p2[i]=(int *)malloc(sizeof(int)*4);//每个指针的字节大小为4
}
for(int i=3;i<3;++i)
{
    free(p2[i]);//从二维开始释放
}
free(p2);
   (3)malloc开辟内存失败,返回值和NULL进行判断
int *p=(int *)malloc(sizeof(int));
if(NULL==p){return NULL;}
   C++:new/delete
   (1)new和delete属于运算符,不属于函数
int *p1=new int;
int *p2=new int(10);/开辟内存并初始化
   (2)delete释放内存的时候,区分释放的是单个元素内存还是数组内存
int **p2=new int *[3];//开辟3个整型数组
for(int i=0;i<3;++i)
{
    p2[i]=new int [4];//数组里存放整形元素/数据
}
for(int i=0;i<3;++i)
{
    delete[]p2[i];//开辟时有[],delete就加上[]
}
delete[]p2;
   (3)new开辟内存失败,抛出bad_alloc异常
try
{
    int *p1=new int;
}
catch(const bad_alloc &err)
{
    cout<<"new失败"<<endl;
}
面试问题:
一.以下动态开辟有何区别?
   int *p=new int [3];//在堆上开辟了三个元素,这三个元素的值为随机值
   int *p=new int [3]();//在堆上开辟了三个元素并初始化,这三个元素的值默认初始化为0
二.new和malloc有何区别?
   1)malloc是函数,而new是运算符;
   2)malloc结果要进行类型强转,而new不用强转;
   3)malloc只能开辟内存,new不仅能开辟内存还能初始化;
   4)malloc开辟失败返回NULL指针,new开辟内存失败抛出bad_alloc异常;
   5)new底层调用的也是malloc。
三.delete和free有何区别?
   1)delete底层调用的也是free来释放内存的;
   2)free释放内存的时候,不区分释放的是单个元素内存还是数组内存;delete释放内存的时候,区分释放的是单个元素内存还是数组内存,因为delete和指针之间需要添加一个[]来表示释放的是数组内存(开辟时候有[]时就添加[])。
eg:
      开辟了一个3行4列的二维数组,每个元素放的都是一个字符串“aaa”,“bbb”等,给每一个元素都初始化成“hello world”,最终并释放掉。
char ***p = new char**[3];
for (int i = 0; i < 3; ++i)
{
    p[i] = new char*[4];
    for (int j = 0; j < 4; ++j)
    {
        p[i][j] = "hello world!";
    }
}     
for (int i = 0; i < 3; ++i)
{
    delete[[]pi];
}
delete[]p;
4.名字空间作用域:namespace
C语言的作用域:全局作用域和局部作用域
C++的作用域:局部作用域,全局作用域和类作用域
namespace作用:解决全局作用域名字冲突的问题。
#include<iostream>
//在系统中已经存在名为std这样一个函数,里面已经定义了cout,cin或是endl等
using std::cout;
using std::endl;
//1)使用using声明后,main函数中就可以调用cout和endl了,但每次只能声明一次,过于麻烦

using namespace std;
/2)用using操作符后,就可以用std中任何被定义的变量或函数了,就很方便了
int main()
{
    cout << " " << endl;
}
5.C++的类和对象
面试问题:
一.面向对象语言有什么四大特征?抽象,封装/隐藏,继承,多态
二.面向对象语言有什么三大特征?封装/隐藏,继承,多态
关系型数据库:SQL Server        MySQL        Oracle
数据库表中的关系:一对一,一对多,多对多
类的创建和表的创建一样:
(1)先看问题场景都有哪些实体(2)找实体的属性(3)找实体之间的关系
类之间的关系:组合,继承

类的访问限定符:public(公有的)
                           private(私有的)
                           protected(保护的)【在之后的继承中出现】

概念一:
1)创建类的目的,是来抽象实体的类型,从实体的属性和行为两方面,得到类的成员变量和成员方法,因为类是实体类型的抽象,所以类类型不占空间

2)用struct和class都可以定义类,不同的是,在没有访问限定符的情况下,class定义的类默认都是private访问限定,struct都是public访问限定
3)分析类类型字节大小的时候,和struct结构体的字节大小计算方式是一样的,都存在字节对齐的问题,唯一不同的,就是C语言的空struct,大小是0,而C++的空class,大小是1
4)类成员方法的定义,可以在类体内直接定义;也可以在类外去定义
方法在类外定义,一定要在方法名字之前,添加类的作用域
void CGoodsInfo::initGoods(char *n, int a, double p)
5)成员方法在类体内实现的话,自动处理成inline函数了
6)查看类对象内存布局,打开vs的命令提示符工具
E:\code\20180413\20180413>cl 20180413.cpp /d1reportSingleClassLayoutCGoodsInfo

7)普通成员变量和成员方法一定要依赖对象才能调用
const int NAME_LEN = 20;//创建类的目的,是来抽象实体的类型
class CGoodsInfo
{
public:
     //一般把实体的行为定义成公有的,称作成员方法/成员函数(指令,在.test段)
    
     //在此声明,在类外定义
     void initGoods(char *n, int a, double p);
     void showGoods();

     //提供一些getXXX和setXXX的方法,在类体内直接定义
     void setName(char *n){ strcpy(name, n); }
     void setAmount(int a){ amount = a; }
     void setPrice(double p){ price = p; }

     char* getName(){ return name; }
     int getAmount(){ return amount; }
     double getPrice(){ return price; }
private:
     //一般把实体的属性都定义成私有的,称作成员变量(在栈上)
     char name[NAME_LEN]; 
     int amount;
     double price;
};

//方法在类外定义,一定要在方法名字的前面,添加类的作用域
void CGoodsInfo::initGoods(char *n, int a, double p)
{
     strcpy(name, n);
     amount = a;
     price = p;
}

void CGoodsInfo::showGoods()
{
     cout << "name:" << name << endl;
     cout << "amount:" << amount << endl;
     cout << "price:" << price << endl;
}
int main()
{
     //用类定义对象,也叫做类实例化了一个对象
     CGoodsInfo  good1;
     //通过访问公有成员方法来访问私有成员变量
     good1.initGoods("shangpin1", 100, 80.0);
     good1.showGoods();

     good1.setPrice(85.0);
     good1.showGoods();

     cout << good1.getName() << endl;
     return 0;
}

6.顺序栈
对象的构造函数和析构函数:
构造函数:SqStack()==>void init()  :  对对象进行初始化
析构函数:~SqStack()==>void relase()  :  在对象内存释放之前,把占用的其他资源释放掉
/*
    1)构造和析构函数的名字必须和类名一样,不能随便起
    2)构造和析构函数没有返回值
    3)构造函数可以任意带参数,构造函数是可以重载的;析构函数是不能带有参数的,因此析构函数只有一个。
*/
const int STACK_SIZE = 10;
class SqStack
{
public:
     //顺序栈的初始化
     void init();
     //释放资源的代码
     void relase();
          //构造函数
     SqStack()
     {
          cout << "SqStack()" << endl;
          mtop = -1;
          mpstack = new int[STACK_SIZE];
     }
      //构造函数
     ~SqStack()
     {
          cout << "~SqStack()" << endl;
          delete[]mpstack;
     }
     //入栈操作
     void push(int val);
     //出栈操作
     void pop();
     //获取栈顶元素
     int top();
     //判断栈空
     bool empty(){ return mtop == -1; }
     //判断栈满
     bool full(){ return mtop == STACK_SIZE - 1; }
private:
     //int mstack[STACK_SIZE];//定义一个宏,在编译时就给了数组大小
     int *mpstack;//用指针做成员变量,就无需在编译时就给大小
     int mtop;
};
//顺序栈的初始化
void SqStack::init()
{
     mtop = -1;
     mpstack = new int[STACK_SIZE];
}
//释放资源的代码
void SqStack::relase()
{
     delete[]mpstack;
}
//入栈操作
void SqStack::push(int val)
{
     if (full())
          return;
     mpstack[++mtop] = val;
}
//出栈操作
void SqStack::pop()
{
     if (empty())
          return;
     --mtop;
}
//获取栈顶元素
int SqStack::top()
{
     if (empty())
          throw "stack is empty!";
     return mpstack[mtop];
}
int main()
{
     /*
     定义对象需要两步
     1:给对象分配内存
     2:给对象调用构造函数
     */
     SqStack stack1;  // stack[STACK_SIZE]   top
     //stack1.init();

     stack1.push(10);
     stack1.push(4);
     stack1.push(56);
     stack1.push(21);
     stack1.push(9);
     while (!stack1.empty())
     {
          int val = stack1.top();
          cout << val << " ";
          stack1.pop();
     }
     //stack1.relase();
     SqStack stack2;
     stack2.push(10);
     stack2.push(4);
     stack2.push(56);
     return 0;
     /*
     栈上的对象,在return处,自动调用对象的析构函数
     */
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章