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
理解复杂数组的声明(难点)
不可以将数组的内容拷贝给其他数组当作初始值,也不能用数组为其他数组赋值。
-
int a[3] = {0,1,3};
-
int a1[] = a; //错误
-
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();
}