目录
一、成员函数、对象拷贝、私有成员
1、综述
自实现time类
二、构造函数详解、explicit、初始化列表
1、构造函数
2、隐式转换和explicit
三、 inline、const、mutable、this、static
1、在类定义中实现成员函数,inline
2、成员函数末尾的const(常量成员函数)
3、mutable(不稳定,容易改变的意思),mutable的引入正好是为了突破const的限制
4、this指针的指向
5、static
四、类内初始化、默认构造函数、=default、=delete
1、类内初始化
2、=default、=delete
类与默认函数
=default
=delete
一、成员函数、对象拷贝、私有成员
1、综述
类是我们自己定义的数据类型(新类型)
设计类是要考虑的角度:
- (1)站在设计和实现者的角度来考虑
- (2)站在使用者的角度来考虑
- (3)父类、子类
一个类就是一个用户自己定义的数据类型
一个类的构成:成员变量、成员函数。
自实现time类
Time.h:
#ifndef __MYTIME__
#define __MYTIME__
class Time
{
public:
int Hour;
int Minute;
int Second;
void initTime(int tmphour, int tmpmin, int tmpsec);
private:
int Millisecond;
private:
void initMillTime(int mls);
};
#endif
Time.cpp:
#include "Time.h"
//其中这两个冒号叫:作用域运算符,表示initTime函数属于Time类。
//可能有多个不同的类,其他类中也可能有叫initTime()的成员函数,所以这里必须用Time::来表明该函数属于Time类
void Time::initTime(int tmphour, int tmpmin, int tmpsec)
{
Hour = tmphour; //注意到,成员函数中可以直接使用成员变量名
//哪个对象调用的该成员函数,那么这些成员变量就属于哪个对象。可以理解成类成员函数知道哪个对象调用的自己
Minute = tmpmin;
Second = tmpsec;
initMillTime(0);
}
void Time::initMillTime(int mls)
{
Millisecond = mls;
}
main.cpp:
#include#include #include "Time.h" using namespace std; //后面再使用诸如std::cout时就可以简写成cout了; int main() { Time myTime; myTime.initTime(11, 14, 5); //这就是调用成员函数(使用成员函数) cout << myTime.Hour << endl; //11 cout << myTime.Minute << endl; //14 cout << myTime.Second << endl; //5 Time myTime2 = myTime; Time myTime3(myTime); Time myTime4{ myTime }; Time myTime5 = { myTime }; myTime5.Hour = 8; Time myTime6; myTime6 = myTime5; //通过赋值操作来拷贝对象 return 0; }
二、构造函数详解、explicit、初始化列表
1、构造函数
父类的构造函数必须要是public属性的,否则被子类继承后无法初始化父类,构造函数不可以手工调用,否则编译就会出错,构造函数一般为public,因为系统要调用构造函数,只有为public,才能被外界调用。
2、隐式转换和explicit
在声明构造函数时加上explicit,限制隐式类型转换。
三、 inline、const、mutable、this、static
1、在类定义中实现成员函数,inline
类内的成员函数实现其实也叫类内的成员函数定义。
一般,time.h放函数声明,time.cpp放函数实现。
这种直接在类的定义中实现的成员函数(在time.h中实现的成员函数),会被当做inline内联函数来处理。
2、成员函数末尾的const(常量成员函数)
const:表示常量,在成员函数末尾的const,不但要在声明中增加const,也要在定义中增加const
const修饰this指针,表示不能通过这个成员函数修改成员变量。
const对象只能调用常量成员函数、普通对象既能调用普通成员函数也能调用常量成员函数。
3、mutable(不稳定,容易改变的意思),mutable的引入正好是为了突破const的限制
用mutable修饰成员变量,表示这个成员永远处于可以被修改状态,即便是在const结尾的成员函数中也可以修改。
4、this指针的指向
普通成员函数中,this指针是 指向非const对象 的const指针(即this指针指向不可以改变,但是this指针指向的空间的值可以改变);
常量成员函数中,this是 指向const对象 的const指针。
5、static
在类中定义的static成员函数和static变量,归所有类对象共有。即所有这个类对象操作的static变量,都是指向同一块空间的。
static成员函数不能操作非static成员变量。
四、类内初始化、默认构造函数、=default、=delete
1、类内初始化
在c++11里,我们可以为类内成员变量提供一个初始值。那么可以在创建对象的时候,这个初始化值就用来初始化该成员变量。
2、=default、=delete
c++11标准中引入的。
类与默认函数
在 C++ 中声明自定义的类,编译器会默认帮助程序员生成一些他们未自定义的成员函数。这样的函数版本被称为” 默认函数”。这样的函数一共有六个:
- 无参构造函数:创建类对象
- 拷贝构造函数:拷贝类对象
- 移动构造函数:拷贝类对象
- 拷贝赋值函数:类对象赋值
- 移动赋值函数:类对象赋值
- 析构函数 :销毁类对象
在 C++ 语法规则中,一旦程序员实现了这些函数的自定义版本,则编译器不会再为该类自动生成默认版本。
在 C++11 标准中称 = default 修饰的函数为 缺省函数,而称 =delete 修饰的函数为删除函数或者显示删除函数。
=default
用于显示要求编译器提供 合成版本(默认为缺省版本) 的四大函数(默认构造、拷贝、析构、赋值),必须用在含有默认合成函数的函数上。
使用 =defaut 指定的默认函数和类提供的默认函数是等价的 。
已经定义了有参数构造函数,编译器不再生成默认构造函数,可以通过 =default 让默认构造函数恢复,不能使用 =default 修饰这六个函数以外的函数。
class Base
{
public:
Base() = default; //编译器能够为这种 =default 的函数自动生成结构体(相当于默认无参的构造函数)
Base(const Base& obj) = default; //定拷贝构造函数为默认函数
Base(Base&& obj) = default; //指定移动构造函数为默认函数
Base& operator= (const Base& obj) = default; //指定复制赋值操作符重载函数为默认函数
Base& operator= (Base&& obj) = default; //指定移动赋值操作符重载函数为默认函数
~Base() = default; //指定析构函数为默认函数
};
// 在类定义之外指定成员函数为默认函数
=delete
告诉编译器,不生成默认的那些成员。可以用在任意函数上(除了析构函数),必须出现在函数第一次声明时。
显式删除可以避免用户使用一些不应该使用的类的成员函数。
使用这种方式可以有效的防止某些类型之间自动进行隐式类型转换产生的错误。
class Base
{
public:
Base() = default; //生成默认的无参构造函数
Base(const Base& obj) = delete; //让程序员显示的禁用这个个函数,禁止调用拷贝构造函数
Base& operator= (const Base& obj) = delete; //阻止赋值
};
int main()
{
Base b;
Base tmp1(b); // error
Base tmp = b; // error
return 0;
}
class Base
{
public:
Base(int num) : m_num(num) {} //自己实现的单参数构造函数
Base(char c) = delete; //禁用带 char 类型参数的构造函数,防止隐式类型转换(char 转 int)
void print(char c) = delete;//禁止使用带 char 类型的自定义函数,防止隐式类型转换(char 转 int)
void print()
{
cout << "num: " << m_num << endl;
}
void print(int num)
{
cout << "num: " << num << endl;
}
private:
int m_num;
};
int main()
{
Base b(97); // 'a' 对应的 acscii 值为97
Base b1('a'); // error。对应的构造函数被禁用,因此无法使用该构造函数构造对象
b.print();
b.print(97);
b.print('a'); // error。对应的打印函数被禁用,因此无法给函数传递 char 类型参数
return 0;
}



