C++ primer 阅读笔记------------类

该博客用于记录自己在阅读过程中不懂的知识点,很少用到但比较重要的知识点以及模棱两可的知识点

一个类每个对象都有自己独立的存储空间存放各自的数据成员,然而成员函数的代码段在内存中只有一份,所以为了保证每个对象访问成员函数时针对的都是自己的数据成员,所有便有了this指针,每个成员函数都有一个隐式形参

T*const this(指向非常量版本的常量指针),它的值指向当前正在调用它的对象的起始地址,所以成员函数中对数据成员的操作前面都包含有一个this→,例:

class myclass{

public:

    int returnI() {return i}

private:

    int i;
}

myclass test; //此处忽略构造函数,后面再提

当使用test.returnI();时,其实会变成下面这样

myclass::returnI(&test);

函数内部会变成:

return this→i; //这几行代码是伪代码用于理解this的使用

this指针也是一个变量,所义说它必须遵守初始化规则,即不能将其绑定在一个常量对象上,所以常量对象不能调用普通的成员函数(调用函数会隐式的执行一个this指针的绑定,而这显然不符合初始化规则)。但事实上我们可以显式的将this指针指定为指向常量的常量指针,这样做必须保证这个成员函数不能改变调用它的对象的内容,当函数内容不会改变对象内容时,我建议这样做。

int returnI() const{return i} //参数列表后的const显式的指明该函数中的this是指向常量的常量指针,

当我们定义的某个成员函数类似与某个内置运算符时(+,-,*,/等),我们因该尽量模仿这个运算符,内置运算符将左侧的运算对象当成左值返回,例:

a+ b + c; //实际上是a+ b返回的对象再去+c

所以如果某个函数的行为类似内置运算符时,我们的返回值应该是一个左值引用,例:

myclass& add(const myclass &cl1){ //myclass的成员函数

    i + = cl1.returnI();

    return *this;

}

构造函数不能声明为const,当创建const对象时,该对象只有在构造完毕时才会获得const属性,这就意味着构造const对象的过程中可以向其写值

当类中存在构造函数时,编译器将不会生成默认构造函数

可以使用=default来定义默认构造函数

myclass()= default;

当定义的构造函数使用初始化列表初始化时,被初始化列表忽略的成员变量将会执行默认初始化

简单的情况下编译器将会为类自动的合成执行拷贝,赋值,销毁的操作,但某些情况下,自动合成的版本会无法正常工作(挖坑,,后面再提);

struct和class唯一的区别仅仅只是默认的访问权限不同,class是private,struct是public

类允许其他类或者函数访问其私有成员,方法是友元;

friend 函数声明

友元不是类成员,所以不受访问限定符的影响。

友元的声明并非通常意义上的函数声明,所以再进行一次普通的函数声明;

类中定义类型的别名一样有访问限制,且类型成员(类型别名成员)与普通成员不一样,它遵守先定义后使用,所以一般在开头定义;

定义在类内部的函数被自动定义为内联函数,即使在类内部声明为普通函数,也可以在类外定义的时候显式的设置为内联函数。

假如为们希望在一个const成员函数内依然可以改变某个数据成员,我们可以将其定义成:

mutable int number1;

就像函数一样,我们也能将类的定义和声明分开:

声明:class myclass;

这种声明被称为前向声明,在声明之后定义之前它是一种不完全类型,此时可以定义指向这种类型的指针或引用,也可以声明(但不能定义)以其为参数类型或者返回值类型的函数,此时编译器只是知道了有该种类型存在,而并不知道它的内容是怎样,到底需要多大的内存空间,由此可以知道,我们并不能在一个类中建立它自己的对象,但是可以建立指向它的指针;

类域内定义的友元函数调用时必须具有该类类型的实参,因为当调用一个友元函数时,名字搜索域也包含与实参关联的那些名称空间和类中的名字

友元函数就算定义在类内部也必须在外面声明

一般来说内层作用域可以重新定义外层作用域中的名字,但是在类中,改名字如果代表一种类型,则不能重新定义

如果没有在构造函数的初始化列表中初始化数据成员,则这些初始化将会在函数体之前执行默认初始化,换句话说,你的数据成员将会执行两次赋值,第一次默认初始化,第二次你的代码显式赋值,如果该数据成员是const(const一旦被初始化后便不能再赋值)或者引用(引用不能二次绑定)的话,则会发生错误,同样的,当成员属于某种没有定义默认构造函数的对象时也会发生错误。

构造函数初始化列表的执行顺序与数据成员的定义顺序相同,如果一个成员的初始化由另外一个成员作为右值的话,顺序就很重要了

委托构造函数,顾名思义,就是某个构造函数初始化时调用另外一个构造函数来帮他初始化,例:

    myclass(intnum1): i(num1) {}
    myclass(intnum2): myclass(num2) {}

类中的所有成员必须初始化,意味着不能默认初始化的数据成员(如类类型)必须手动初始化

当类的构造函数只需要一个实参时,可以使用隐式的类型转换将实参类型转换为类类型,例:

class myclass{

public:

  myclass(intnum1, int num2 = 2): i1(num1), i2(num2){}

    int testclass(const myclass & test){

    return test.i1 + test.i2;

}


private:

    int i1;

    int i2;

};

int main()

{

    myclass class1(2);

    cout << class1.testclass(1) << endl; //调用testclass函数时理应传入一个myclass类型的实参,但为什么为传的是
                                                                            //一个整型的1,却还是成功了呢?因为myclass的某个构造函数只需要一个实参,
                                                                            //此时我们传入1的时候它隐式的执行了一个构造函数,构造了一个临时的对象,
                                                                            //此时应注意,虽然构造函数有两个形参,但有一个有默认实参,所以是一个只需要
                                                                            //一个实参的构造函数

return 0;

}

还有一点必须提,编译器只会自动执行一步类型转换,也就是说假如形参需要的是string类型的,我们传入一个字面值是不行的,因为它会先转换成string类型,再转换成类类型

如果我们不希望编译器执行隐式的类型转换,则可以在构造函数前面加上explicit关键字,只需要在声明时加

在上面的例子中:

myclass class1(2);

也可以写成:

myclass class1 = 2; //拷贝的形式

但如果加了explicit关键字则不能以拷贝的形式写,尽管加上explicit关键字后不能隐式的转换,但我们可以使static_cast

执行显式的转换

聚合类的特性:

所有成员都是public的

没有定义任何构造函数

没有类内初始值

没有基类,也没要virtual构造函数(后面讲)

允许使用花括号扩起来的初始值列表初始化聚合类的数据成员

字面值常量类是聚合类或者满足下列要求的类

数据成员都是字面值类型

含有constexpr构造函数(普通的构造函数不能是吃哦是const的)

如果含有类内初始值,则必须是常量表达式,或者成员是类类型的,则必须使用成员自己的constexpr构造函数

类的析构函数必须使用默认的

constexpr构造函数可以声明成=default或者删除函数的形式(挖坑后面填)

静态成员函数属于类,不与任何对象绑定,所以它们不包含this指针,且不能声明为const。

静态成员函数定义时不用重复static关键字,只需要在声明时加上就行了。

因为静态数据成员不属于任何对象,所有构造函数并不能初始化它,应该在类外定义和初始化静态成员,且只能定义

一次,且应该是全局的

其实我们也能在类内定义静态数据成员,但必须保证该成员是字面值常量类型的constexpr,初始值必须为常量表达式

静态数据成员可以是不完全类型,它的类型就是该类的类型(因为类定义对象时需要分配内存,所以普通数据成员如果使用该类类型就不知道该分配多少内存空间,而静态数据成员不属于任何类,所有不存在定义时分配内存的问题),静态数据成员还可以作为默认实参,而这些都是普通数据成员不能做的地方

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值