C++ Primer第五版笔记

2.3.1节

(1)int&;

这里的&不是取地址符号,而是引用符号,引用是C++对C的一个重要补充。变量的引用就是

变量的别名,讲的通俗一点就是另外一个名字,比如:“张三这个人在家里,老爸老妈叫他

三娃子,那么这个三娃子就是指张三这个人,如果叫张三去做某事,就是叫三娃子去做某事,

这两个名字指的是同一个人。”同样可以理解如果变量b是变量a的引用 那么无论a,b中任

何一个值改变,另外一个也相应的改变,在声明一个引用时,必须同时使之初始化,即声

明它代表哪一个变量。请注意:由于引用不是独立的变量,编译系统不给它单独分配存

储单元,因此在建立引用时只有声明没有定义,只是声明它与原有的某一变量的关系。

在声明一个变量的引用后,在本函数执行期间,该引用一直与其代表的变量相联系,不能

再作为其他变量的别名。说得简单点:张三和三娃子是指同一个人,不能李四也叫三娃子,

如果可以这样,叫三娃子去做什么,是叫李四呢还是张三呢,这就会乱套了。所以在C++中

一个引用变量只能对应一个原始的变量,不能对应两个或多个原始的变量;(来源于网址:https://blog.csdn.net/cj151525/article/details/83714835

(2)\

int i=42;

const int&r1=i;

const int&r2=0;

解释:前两行就是正常的创建int,然后让r1常量引用i,使得r1和i等价,第三行也是可行的,但是内容更为丰富:

const int&r2=0;相当于编译器创建一个临时变量,但是外部不可访问,int ii=0;const int& r1=ii,但没人能访问ii,所以编译器就没问题。相比较的int &r1=0;这个就不可以,因为编译器认为你既然这么设定的话,就有可能改r1所制定的对象(就是临时变量ii,但没人能访问到,所以等于白做),就干脆不允许你这么做。

(3)const 与指针

r1是一个指针,有指针自己的地址和自己地址所存储指向对象的地址,而不同的const位置就是为了这个目的

int *const r1=&i   //指针自己的地址不能改变,

const int * r1=&i//指针所指向的地址不能变

const int *const r1=&i//都不变(从右往左读,const r1,说明r1自己的地址不变,然后加上int*就是所指的对象,然后再是const,说明所指对象不变,所指对象的值不能从通过*r1=...进行改变。)

3.2.3

C++11特性其一:

string s("HI");

for(auto &c:s)

{

c=toupper(c);

cout<<s<<endl
}

3.3.2

vector<int>v1{0,1}元素2个

vector<int>v2(10,2)元素10个

vector<string>v3{10}元素10个

vector<string>v4{10,"Hi"}元素10个

3.27

理解复杂数组的声明(难点)

不可以将数组的内容拷贝给其他数组当作初始值,也不能用数组为其他数组赋值。

  1. int a[3] = {0,1,3};

  2. int a1[] = a; //错误

  3. a2 = a; //错误

int *a[10];  //a数组含有10个指针整形
int &a[10];  //错误,不存在引用的数组
int (*a)[10]; //a是一个指针,指向一个含有10个整数的数组
int (&a)[10]; //a是一个引用,引用一个含有10个整数的数组
int *(&a)[10]; // a是数组的引用,数组含有十个指针
3.5.3

C++11引入begin和end对于数组。

int a[2]={1,2};

int *i=begin(a);

int *j=end(a);

3.5.4

char ca={'0','1'};

int a=strlen(ca);//错误,没有以空字符结束

string large=a1+''+a2;

strcpy(large,a1);

strcat(large,a2);

6.4.1

重载作用域:如果在内层重载某个函数,那么会自动屏蔽外部作用域的同名实体,在不同的作用域中无法重载函数名。

正确:

void printf(const string &);

void printf(int);

void printf(double);

void test1(int vial)

{

printf("Const");

printf(32.2);

printf(2);

}

6.5.1默认实参:传参如果没有的话,可以为默认值

typedef string::size_type sz;

string screen(sz ht=24,sz wid=80,char background=' ');

string window;

window=screen();//24,80, //

window=screen(30);//30,80, //

window=screen(30,90,'1');//30,90,1//

window=screen('?')//64,80, //无法实现仅改变后面而默认前面的情况

一旦函数的某个形参被赋予了默认值,他后面所有的参数都必须有默认值

声明:

string screen(sz ,sz t1=20,char background=' ');//正确

string screen(sz t1=20 ,sz ,char background=' ');//错误

6.5.2内联函数

格式:inline void temp:: print_amount(){ cout << amount << endl;} 

含义:相当于告诉编译器不用进行函数调用

五、使用注意事项

 1.内联函数不能包括复杂的控制语句,如循环语句和switch语句;

  2.内联函数不能包括复杂的控制语句,如循环语句和switch语句;

  3.只将规模很小(一般5个语句一下)而使用频繁的函数声明为内联函数。在函数规模很小的情况下,函数调用的时间开销可能相当于甚至超过执行函数本身的时间,把它定义为内联函数,可大大减少程序运行时间。

constexpr

constexpr是C++11中新增的关键字,其语义是“常量表达式”,也就是在编译期可求值的表达式。最基础的常量表达式就是字面值或全局变量/函数的地址或sizeof等关键字返回的结果,而其它常量表达式都是由基础表达式通过各种确定的运算得到的。constexpr值可用于enum、switch、数组长度等场合。

6.5.3

assert函数,属于预处理器范围,不用在头文件中引用。效果如果不满足括号则输出信息以及中止操作。

例子:

assert(word.size()>threshold);

6.7函数指针

*pf=lengthCompare//等价于&lengthCompare

bool *pf(const int, const string&)//错误

bool (*pf)(const int, const string&)//错误

bool a=(*pf)(12,"123");

函数指针形参:

void BG(const string&,const int,bool (*pf)(const int, const string&))pf会自动变成函数指针

typedef bool abc(const int,const string&);

typedef decltype(lengthCompare) *aaa;

abc df(int a,inv);返回函数指针abc

int (*ff(int))(int *, int);

解析:先看ff(int)是一个函数命名,然后返回一个指针,才有了左边的*,再往外一层是这个函数的形式,包含形参和返回值的设定。

下面的例子:

typedef double (*PF)(double *dbData, int iSize);     // 定义函数指针类型

52     PF GetOperation(char c)                              // 根据字符得到操作类型,返回函数指针

53     {

54         switch (c)

55         {

56           case 'd':

57                     return GetMax;

58           case 'x':

59                     return GetMin;

60           case 'p':

61                     return GetAverage;

62           default:

63                     return UnKnown;

64           }

65     }

66 printf("result is %lf\n", GetOperation(c)(dbData,iSize));   // 通过函数指针调用函数

 

7.1 this 指针

更深入的理解:可参考http://c.biancheng.net/view/170.html,里面从C语言没有class和成员函数的基础上,在C语言上实现成员函数的功能,换而言之,在C语言中,你可以创建一个结构体,然后成为全局变量,但你要有一个成员函数,说明你要类的内部参数,所以这个函数和成员之间的挂钩就是this指针,他本身就是一个指针,指向你想要的那个成员地址,例如:
void test(struct CC* this,int t),此时,你就可以通过this所指的结构体,将得到该结构体的内部成员变量。

而在C++中你在成员函数中用到成员变量,this->a和a是没有区别的,所以派上用场的地方在于return,没有一个东西可以代表这个类的地址,所以才有this指针的出现。

 

this相当于隐式的被传入对象的地址,this 的类型是Sales_data *const(指针的地址不变),可以通过设置const成员函数称为指向常量的常量指针:

std::string isbn ()const{return this->bookno;}

this 默认是常量指针,意味着该指针自己的地址不能变,但能改变所指向对象的内容(如果相反的则被称为指向常量的指针,即指向的对象不能变,但是指针自身的地址可以变。)

常量成员函数

std::string Sales_data::isbn(const Sales_data *const this)

{return this->isbn}//伪代码

struct Sales_Data{

Sales_Data()=default;

Sales_data(const std::string & s ):bookNo(s){}

Sales_data()

}

7.1类的成员定义优先于函数,所以可以在未定义成员前在函数中使用成员

7.12  struct 和class的唯一区别就在于class中可以有private

7.14只有函数没有构造任何构造函数时,才会有默认函数

Sales_data()=default;(手动添加的默认构造函数)

构造函数初始列表:(在类的内部构造函数)

两种举例

Sales_data(const std::string &s):bookNo(s) {}

//这个等价于Sales_data(const std::string&s):bookNo(s),units_sold(0),revenue(0){}

Sales_data(const std:stding&s,double a,unsigned n):bookNo(s),units_sold(n),revenue(n*p){}

在类的外部构造构造函数

Sales_data(const std::istream &);//类内

Sales_data::Sales_data(std::istream &is)//类外

{

read(is,*this);

}

这个相当于已经初始化,然后用read把字符串传过去。

7.3.1 在类中可以定义一个类型成员,有两种方式:

1)typedef std::string::size_type pos;

2)using pos=std::string:size_type;

public:

Screen(pos a,pos b,char c):height(a),length(b),content(a*b,c){}

private:

pos height=0,length=0;

std::string content;

成员函数重载的意思,就是函数只跟输入量匹配就可以调用,名字一样无所谓,只要形参不同就好

private:

mutable size_t access_str;

加了mutable即使是const也可以改变

7.33

class kin

{

Screen Window;

kin *top;

kin *bottom;

}

这样也是可以的。

7.3.4如果一个类需要用到另一个类的private,只需将该类设为友元即可:

class Screen

{

friend class window_scr;

//或者将成员函数作为友元也可以

friend void window_scr::clear(SceenIndex); 

}

7.5.5聚合类:

满足1)所有成员都是public 2)没有构建构造函数3)没有类内初始值4)没有基类

可以直接进行{}赋值

struct Data{

int t;

string s;

}

Data a={10,'s'};

7.6声明静态成员

静态成员可以是public或者private

静态成员不与对象绑在一起,没有this

但可以正常的使用

例如:

class Test{

 public :

static int t;

static void rate(double);

}

double r;

Test::rate(r);

Test a;

Test *aa=&a;

a.rate(r);

aa->rate(r);

8.1 iostate

static_cast 、dynamic_cast、reinterdivt_cast、和const_cast

!!!!

Template模版:用处:当你所用到的函数类型不确定时才会出现,例如stl容器中,vector可以对于string等都起到作用。

Template模版可以定制函数和对象,可参考如下例子:

 

//stack.h
template <typename T>void swap(T &a,T &b);
template <typename T>void swap(T &a,T &b)
{
    T temp;
    temp=a;
    a=b;
    b=temp;
}
template<class A>class Stack{
    public :
        Stack(int b);
        ~Stack();
        void push(A t);
        void pop();
        void display();
    private:
        A* pt;
        int m_max_size;
        int size; 
};
template<class A>void Stack<A>::display()
{
    if (size==0)
    {
        std::cout<<"Empty"<<std::endl;
        return; 
    }else
    {
        for(int i=0;i<size;i++)
        {
            std::cout<<pt[i]<<std::endl;
        }
    }
    return;
}
template<class A> Stack<A>::Stack(int b){
    m_max_size=b;
    size=0;
    pt=new A[m_max_size];
     
}
template<class A>Stack<A>::~Stack()
{
    delete []pt;
}
template<class A>void Stack<A>::push(A t)
{
    if(size==m_max_size) {
        std::cout<<"Full!"<<std::endl;
        return;
    }
    pt[size++]=t;
}
template<class A>void Stack<A>::pop()
{
    if(size==0) 
    {
        std::cout<<"Empty!"<<std::endl;
        return;
    }
    size--;
}

 

 

 

 

 

//main.cpp
#include<stdio.h>
#include<iostream>
#include "stack.h"
int main()
{
    int a=1,b=2;
    swap<int>(a,b);
    std::cout<<a<<b<<std::endl;
    Stack<int> intstack(2);
    intstack.push(1);
    intstack.push(2);
    intstack.push(3);
    intstack.pop();
    intstack.push(3);
    intstack.display();
     
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值