C++入门

本文介绍了C++的基础知识,包括全局与局部作用域、缺省参数、函数重载、引用的使用规则、返回值类型与函数重载的关系、内联函数的注意事项、类型转换、范围for循环、类的构造函数、析构函数、拷贝构造和赋值运算符的实现,以及运算符重载等核心概念。强调了类成员函数、对象成员变量的存储和初始化,并探讨了类的访问权限和构造函数的自动调用机制。
摘要由CSDN通过智能技术生成

目录

1.c++入门知识点

2.类和对象的知识点


1.c++入门知识点

1.::域限定作用符,如果左边什么都没有写,表示在全局找

int a=5;
int mian()
{
    int a=1;
    cout<<a<<endl;//这个打印的结果是1
    cout<<(::a)<<endl;//使用了域作用限定符,在全局里面找a,使用打印的结果为5
}

2.缺省参数不可以在声明和定义同时出现,一般推荐在声明给,定义时就不要给了,因为如果当声明和定义时给不一样的缺省值,我们就不知道改用哪个了。

3.返回值类型不能构成函数重载,因为在调用的时候编译器不能很好的进行区分

void func(int a,int b)
{

}
int func(int a,int b)
{
    return b
}
int main()
{
    func(3,5);
    func(5,6);
}

4.引用的 使用规则

(1)引用定义的变量必须要初始化

(2)引用只能引用一个实体,不能指向多个实体

(3)引用可以给被引用的变量再次进行引用

5.只要出了作用域还在的变量,就可以使用引用返回

6.传引用的一个好处就是可以改变传引用值,另一个好处就是可以减少临时拷贝

7.这个是错误的,因为ret是引用 而count是传值返回,返回的是临时变量,临时变量具有常性,不能被修改,如果要变成正确的话就要加个const修饰 这是权限的平移 引用和指针的权限是可以平移和缩小的 但是不可以放大
//正确写法:const int& ret=count(5);

int count(int c)
{
c++;
return c;
}
int main()
{
int& ret=count(5)
}


8.像强制类型转化和隐式类型转化都是会产生一个临时变量的
例如int a=10; double& b=i;//是错误的,因为这是强制类型转化,会产生临时变量
const double& b=i;//是正确的
9.内联函数不建议声明和定义分离,一般建议直接在.h里面写
10.typeid(b).name()这个函数的作用是获取b的类型
例如如果是int 就获取到int类型,如果是int*,就获取到int*类型
11.范围for—语法糖写法

int array[]={1.2.3.4.5.6.7};
for(auto e:array)//不一样要用e,用其他变量也可以表示
{
    cout<<e<<endl;
}
//这个是赋值给e对象,数组里面的内容是不会改变的
如果写成auto& e:array就会改变e的值
范围for不适应一种情况
void func(int array[])
{
   for(auto x:array)
   {
    cout<<x<<endl;
   }
}
//因为传参过去后array就变成了指针 而指针不可以使用范围for


12.auto不能使用的场景
(1)不能用于函数传参,例如void func(auto a)
(2)不能用于声明数组的类型
(3)auto可以定义多个变量,但是每个变量的类型都必须一致,例如auto a=1,b=1.1是不可以的
13.在c++里面空指针要用nullptr,而不用NULL,因为在c++里认为NULL是0
14.使用class类的时候,默认是private,私有的意思是不限定类里面的权限,而是限制类外面的权限,让外面的人不能访问到里面
15.struct类默认是public,因为要兼容c语言
16.声明和定义的区别:声明就是那个还没有开空间,而定义就是实实在在的开了空间
17.每个对象的成员变量都是不一样的,需要独立存储,而每个对象的成员函数是一样的,放到共享公共区域(代码段),这个放到代码段指的是指令在代码段 而函数的参数和局部变量(指令运行起来需要的相关数据)还是在栈区。
18.当一个类里面没有成员变量的时候,它的大小为1,这个1个byte不存储有效数据,仅仅是为了占位,表示实例化对象存在过
19.c++类里面有一个this的指针,只不过这个this的指针是由编译器做的,不能由我们控制
例如 void func(date* this,int year,int month ,int day),这个this指针被隐藏了,不会显示出来
20.this指针可以为空,但是不能对空指针进行解引用否则就发生错误
void func()
{}
例如 Date* ptr=nullptr,ptr->func();//正常运行,因为没有对空指针进行解引用,这个用法同于(*ptr).func()

21.如果声明和定义分离,那么定义函数就要加上域作用符例如 void Date::func()
{},而如果都写在一个类里面就不要添加
22.构造函数是一个特殊的函数,他是由编译器自动调用的,且构造函数的名字与类名相同,没有返回值(意思是不用写void),构造函数可以重载,构造函数传无参的时候写法是Stack st;有参数的时候是Stack st(4);传无参的时候不能带括号的原因:这样做会与函数的声明(返回值是Stack ,函数名是st)一样,编译器不能很好的理解他是要实例化对象还是要声明函数。
23.C++里调用类里面的函数的写法是st.push(1);而C语言是stackpush(1)。

2.类和对象的知识点

1.析构函数的作用不是完成对象本身的销毁,而是完成对资源对象的清理,像new  malloc 这样的就需要析构函数,如果不需要清理的话,就不会调用析构函数,析构函数不能支持函数重载
2.构造函数如果我们不写,编译器会自动生成,如果写了,那么编译器不会自动生成(但凡我们只要写了一个有参数的构造函数,但是没有写缺省值,如果传无参的,那么编译器会报错),并且编译器自动生成的构造函数对内置类型不作任何处理(随机值),但是对自定义类型会完成初始化
3.如果一个类里面是内置成员,虽然不能生成构成函数,但是我们可以在声明得时候给缺省值,但是要注意这不是初始化
4.如果是内置类型和自定义类型混用得话,那么编译器还是只会对自定义类型完成初始化,但是对内置类型还是不作处理
5.无参构造函数,全缺省构造函数,和编译器默认生成的构造函数都可以叫做是默认构造函数,默认构造函数可以认为是不传参就可以调用构造函数,一般建议,每个类都提供一个默认构造函数
6.拷贝构造函数是构造函数的一个重载函数,拷贝构造函数必须的参数只有一个且必须是类类型对象的引用,否则会引起无限拷贝构造函数
构造函数写法
Date(int year=1)
而拷贝构造函数写法是Date (Date& d)
{
  _year=d._year
}
7.对于自定义类型的传参都要调用拷贝构造函数,例如

class Date
{
 public:
    Date(Date& d)
    {
        _year=d._year;    
    }
}
void Func(Date d)
{
    
}
//如果是传引用传参就不需要调用拷贝构造,
//因为d是d1得别名,并且指针也不需要,因为指针是内置类型
void func(Date& d1)
{}
int main()
{
    Date d1;
    func(d1);
    func2(d1);
}


这边我们使用func函数 但是因为传参的类型是自定义类型 所以编译器会调用拷贝构造函数 会进入到Date类里面,当拷贝构造函数完成后才会继续到func函数里面,这种也被称为深拷贝构造,如果是内置类型,就是浅拷贝构造,浅拷贝构造编译器可以自己驾驭,但是深拷贝构造不行
8.拷贝构造有两种写法,一种是Date d2(d1);另一种是Date  d2=d1;
9.在类里面有一个this隐藏的指针,当我们会返回这个对象时,我们要返回*this,注意这个*不是代表解引用,而是表明this是这个对象的本身

10.C++类里面的析构函数也满足一个栈的特性,也就是先进后出,就是说先进来的后析构,后进来的先析构
11.析构栈的时候,如果用浅拷贝的话,就会导致array指向同一块空间,然后st2先析构,会把array的空间析构,再把st2.array置成空,但是st1.array变成了野指针,因为st2只是把自己的置成空,并不会改变st1的类成员变量值
12.什么情况下需要实现拷贝构造?
自己实现了析构函数释放空间,就需要实现拷贝构造
13.使用运算符重载打印的时候要注意<<的优先级会有些运算符高一些,因此打印的时候一般都建议加上括号
例如cout<<(d1==d2)<<endl
14.注意,这五个操作符不能运与函数重载:
(1).*   (2)::  (3)  sizeof    (4)  ?:(5)  .
15.Date  d2=d1是拷贝构造
d1=d2是赋值运算符
16.写赋值运算符的时候我们函数的返回值一般要求返回*this这个值,这个目的是为了支持连续赋值  d1=d2=d3
17.在C++中,写一个运算符重载时,可能遇到前置++和后置++的问题,因此编译器会默认再后置++的函数参数里添加一个int参数,这个是固定的,并且他没有实际的意义,只是为了能构成运算符重载
18.<<流插入其实是个运算符重载,但是自定义类型不支持,因此当我们写一个类的时候,一般都要需要自己写cout<<d1这种类型的运算符函数
19.当我们把一个类函数写在类里面,那么默认第一个是this,但是我们如果写在外面就为全局函数,那么参数的顺序就是我们可以控制的,但是作为全局函数,是不可以直接访问私有成员的,所以C++访问私有成员一般喜欢用一个友元函数friend,friend void  operator《(ostream& out,const Date& d),为了能支持连续赋值,要把void  operator《(ostream& out,const Date& d)改成ostream&  operator<<(ostream& out,const Date& d)返回值为out
20.写流提取的函数为istream&  operator<<(istream& out,Date& d)返回值为in
21,内联函数是不会进符号表的,当我们声明和定义分离的时候 就会call 符号表去找定义,而又因为内联是不进符号表的 所以会发生链接不上的现象
22.当我们在类里面写函数定义的时候 编译器一般都会把较短的函数当做内联函数来处理
23.
class A
{
public:
    void printf()const
    {
        cout<<_yaer<<endl;
    }
}
int main()
{
    const A aa;
}
这边要加const的原因是 我们实例化对象aa是const A,所以我们不能进行权限的放大,但是因为*this是隐含的参数 我们不能直接改变,因此只能间接添加一个const
24.c++还有一个运算符&也是天选之子,但是实际没有多少意义,一般都不要要求写
Date&  operator&()
{
return   this;
}
25.初始化列表:以冒号为开始,以逗号为分割的数据成员列表,每个成员列表后面的扩号表示初始化值或者表达式,这个一般是用来成员变量里含有被const修饰的对象成员,因为被const修饰的变量只有一次初始化的机会,所以在被定义出来的时候就必须要初始化

class A
{
public:
   A()
     :_x(5)
     ,_a2(5)
  {

  }
private:
  int  _a1=2;
  int  _a2=6;
  const  int  _x;
}


private里面的是缺省值,而构造函数里面的才是定义初始化,也就是说如果初始化列表里面有给初始化的就用初始化,没给得话就是用缺省值
26.有三个类型必须在初始化列表定义
1.const    例如  const  int  _x
2.引用   例如  int &  ref
3.自定义成员(且该类没有默认的构造函数)例如

class B
{
 public:
    B(int x)
    :_b(0)
    {

    }
private:
   int _b;
}
class A
{
 public:
    A()
    _bb(5)
    {
            
    }
    
private:
  B _bb;
}


27.成员变量在类中声明次序就是其再初始化列表中的初始化顺序,与其再初始化列表中得先后次序无关

class A
{
 public:
    A(int a)
    :_a1(a)
    ,_a2(a1)
    {
        cout<<_a1<<_a2<<endl;
            
    }
private:
  int  _a2;
  int  _a1;
}
int  main()
{
    A aa(1);
}


这个结果是1和随机值,因为a2先被定义出来 所以2就要先被初始化 而a1这时候是还没有完成初始化的 所以结果就为随机值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值