[C++ Primer Plus] 类基础知识--类和动态内存分配
各章节知识点:
12.1
一,静态类成员的特点
无论创建了多少类对象,程序都只创建一个静态类变量副本。也就是说,类的所有对象共享同一个静态成员.
class stringBad
{
priviate:
static int num_string;
}
注意,不能在类声明中初始化静态成员变量。因为声明描述了如何分配内存,但并不分配内存。可以使用如下格式来创建对象,从而分配和初始化内存:
int stringBad:: num_string = 0;
但静态数据成员为const整数类型或者枚举型,可以在类声明中初始化。12.1.2
二,声明一个类,C++会自动提供如下成员函数:
1,默认构造,如果没有定义构造;
2,默认析构,如果没有定义;
3,复制构造,如果没有定义;
4,赋值运算符,如果没有定义;
原型如下:
Class_name & Class_name::operator=(const Class_name &)//接受并返回一个只向类对象的引用
5,地址运算符,如果没有定义;
C++11还提供了另外两个特殊的成员函数:移动构造和移动赋值运算符。
三,何时调用复制构造?
每当程序生成对象副本时,编译器都将使用复制构造函数。即:
1,当函数按值传递对象;
2,函数返回对象(按值传递将创建原始变量副本);
3,新建一个对象,并将其初始化为同类现有对象;
12.2.4
四,静态类成员函数
可以讲成员函数声明为静态的,但有两个后果:
1,不能通过对象调用静态成员函数;静态成员函数也不能使用this指针。
如果是公有的静态类成员函数,可以使用类名和作用域解析运算符来调用它。如:
int count = String::HowMany();
2,静态成员函数不与特定的对象相关联,因此只能使用静态数据成员。
五,构造中使用new应注意的事项
1,构造中如果使用new,则在析构中应使用delete;
2,new和delete应该互相兼容,即new->delete,new[]->delete[];
3,如果有多个构造,则必须以相同的方式使用new,要么都带中括号,要么都不带。因为只有一个析构函数,所有的构造都必须与它兼容;
4,应定义一个复制构造,进行深度复制;
5,因定义一个赋值运算符,通过深度复制将一个对象复制给另一对象。要注意检查自我赋值的情况;
12.5.1
六,什么时候调用析构?
1,如果对象是动态变量,则当执行完定义该对象的程序块是(即退栈),将调用该对象的析构函数;
2,如果对象是静态变量,则在程序结束时将调用对象的析构;
3,如果对象是new创建的,则但显示调用delete删除对象时,其析构才会被调用;
12.7
12.7.1
七,嵌套结构和类
在类声明中再声明结构、类、或枚举被称为是被嵌套在类中,其作用域为整个类。这种声明不会创建数据对象,只指明了可以在类中使用的类型。如果在类的私有部分进行,则只能在类中使用。如果在类的公有部分声明,可以在类外使用作用域解析符使用被类声明的类型。如Queen::Node
12.7.1
八,常量成员变变量
1,常量,可以对其进行初始化,但不能给他赋值;
2,常量成员与引用成员相似,即只能在被创建时进行初始化(即使用成员初始化列表)
九,初始化成员列表语法
如果classy是一个类,而mem1,mem2,mem3都是这个类的数据成员,则类构造函数可以使用如下语法来初始化数据成员:
Classy::Classy(int n, int m):mem1(0), mem2(0), mem3(n*m + 2)
{
//...
}
注意:
1,这种格式只能用于构造函数;不用用于构造函数之外的其他类方法;
2,必须用这种格式来初始化非静态(non static)const数据成员;(至少在C++)
3,必须用这种格式来初始化引用数据成员;
12.7.1
九,伪私有方法
如果不想让让类拥有复制和赋值方法,可以将方法定义为私有,并不写其具体实现。如:
class Queen
{
private:
Queen(const Queen & q){} //复制构造
Queen & operator=(const Queen & q) {} //重载赋值运算符
}
1,它避免了本来自动生成的默认方法定义
2,因为这些方法是私有的,不能广泛被使用
那么下面的代码,编译器将报错:
Queen snick(nip);
tuck = nip;
同时对象按值传递或者返回时,都将不可用,则必须采用传递对象引用的方法。后续如果需要支持拷贝和复制,则重新声明复制构造和赋值运算符即可。