1.初始化列表
用于多个对象构造,构造函数和其他函数不同,除了有名字、参数、函数体之外还能有初始化表。
简单使用:
class Person
{
private:
int m_a;
int m_b;
int m_c;
public:
Person(int a, int b, int c) :m_a(a), m_b(b), m_c(c) {}
};
对象作为成员:
class A
{
private:
int m_a;
public:
A(int a) :m_a(a) { cout << "A的有参构造"<<endl; }
~A(){ cout << "A的析构" << endl; }
};
class B
{
private:
int m_b;
public:
B(int b) :m_b(b) { cout << "B的有参构造" << endl; }
~B() { cout << "B的析构" << endl; }
};
class Person
{
private:
A oba;
B obb;
public:
Person(int a, int b) :oba(a), obb(b) { cout << "Person的构造" << endl; }
~Person(){ cout << "Person的析构" << endl; }
};
void test01()
{
Person ob1(10, 20);
}
可以看到按对象成员在类中的定义依次调用他们的构造函数,再调用该类的构造函数,最后先进后出析构。
2.explicit关键字
explicit关键字,禁止通过构造函数进行隐式转换。声明为explicit的构造函数不能在隐式转换中使用
class B
{
private:
int m_b;
public:
explicit B(int b) :m_b(b) { cout << "B的有参构造" << endl; }
~B() { cout << "B的析构" << endl; }
};
void test01()
{
B ob1 = 10; //错误
B ob2(10); //对
}
3.new和delete
3.1和malloc、calloc及reallocation(下面写mcr)比较
(1)mcr返回一个void指针,c++不允许void赋值给其他指针,必须要强制转换。
(2)mcr可能声情内存失败,所以必须判断返回值确保内存分配成功。
(3)mcr不会调用构造函数,free不会调用析构函数。
(4)mcr,free和new,delete不能混搭使用。
3.2new申请基本类型空间
void test01()
{
int *p = NULL;
p = new int;
*p = 100;
cout << *p << endl;
p = new int(200);
cout << *p << endl;
delete p;
}
3.3new申请基本类型数组空间
void test02()
{
int *arr = NULL;
arr = new int[5]{1,2,3,4,5}; //定义+初始化
for (int i = 0; i < 5; i++)
{
cout << *(arr + i) << ' ';
}
delete[]arr;
}
void test03()
{
char *arr = NULL;
arr = new char[32];
strcpy(arr, "lingo");
cout << arr << endl;
delete[]arr;
}
注意:申请时new加[],释放时delete加[]。
3.4new申请类对象空间
class Person
{
private:
int m_num;
char *arr = new char[32];
public:
Person()
{
cout << "默认构造函数" << endl;
}
Person(const char *name, int num)
{
m_num = num;
strcpy(arr, name);
}
~Person()
{
cout << "析构函数" << endl;
}
};
void test04()
{
Person *p = new Person("lingo",20);
delete p;
}
void test05()
{
Person *p = new Person;
delete p;
}
new按照Person申请空间,如果申请成功就会自动调用Person类的构造函数
delete先调用析构函数,再释放堆区空间
4.对象数组
本质是数组,但成员是对象。
Person arr1[5];
Person arr2[5]={Person("lingo",20),Person("lucy",18)};
定义数组时,系统会自动给数组的每个元素调用构造函数
用new申请对象数组
Person *arr=NULL;
arr = new Person[5]{};
delete []arr
5.静态成员(static修饰的成员)
static修饰的成员为静态成员,不管这个类创建了多少对象,静态成员只有一个拷贝,这个拷贝被所有属于这个类的对象共享。
静态成员属于类而不对象。
5.1static修饰成员变量
静态变量再编译阶段就会分配内存空间,对象还没有创建时,就已经分配内存空间。
静态成员必须在类中声明,类外定义。
class Person
{
public:
int num;
static int data;
};
int Person::data = 10;
void test01()
{
cout << Person::data << endl;
Person::data = 20;
cout << Person::data << endl;
Person ob1;
ob1.data = 30;
cout << Person::data << endl;
}
int main()
{
test01();
}
5.2静态成员函数
data静态,在创建对象之前就存在,如果没有实例化对象,却想使用data,就要用到静态成员函数。
class Person
{
private:
static int data;
public:
static int getData()
{
return data;
}
};
int Person::data = 10;
void test01()
{
cout << Person::getData() << endl;
}
注意:
(1)静态成员函数的目的是操作静态成员数据
(2)静态成员函数不能访问非静态成员数据。(静态成员函数内部没有this指针)
(3)普通成员函数可以操作静态成员数据和非静态成员数据。
5.3const修饰静态成员
如果一个类的成员既要实现共享,又要实现不可改变,就可以使用static const 修饰。
class Person
{
private:
const static int data;
public:
const static int getData()
{
return data;
}
};
const int Person::data = 10; //const不能省略
void test01()
{
cout << Person::getData() << endl;
}
5.4两个案例
5.4.1静态成员统计类的实例化对象的个数
class Person
{
public:
static int count;
Person() //无参构造
{
count++;
}
Person(Person *ob) //拷贝构造
{
count++;
}
~Person()
{
count--;
}
};
int Person::count = 0;
void test01()
{
cout << "现存对象数:" << Person::count << endl;
Person ob1;
cout << "现存对象数:" << Person::count << endl;
{
Person ob2;
Person ob3;
cout << "现存对象数:" << Person::count << endl;
}
cout << "现存对象数:" << Person::count << endl;
}
5.4.2单例模式设计——打印机
步骤一:在单例类内部定义一个singleton类型的静态对象,作为外部共享的唯一实例
步骤二:提供一个公共静态的方法,让客户可以访问它的唯一实例
步骤三:为了防止外部实例化其他对象,将其构造函数设计为私有
class Printer
{
private:
static Printer *singlePrint; //创建这个类的唯一一个对象
Printer() { count = 0; } //私有化构造函数
Printer(const Printer &ob){}
public:
int count;
static Printer* getSPrint() //提供这个对象的访问方法
{
return singlePrint;
}
void printText(const char *str) //功能实现
{
cout << "打印" << str << endl;
count++;
}
};