C++类的定义

静态数据成员

  • 用关键字static声明
  • 为该类的所有对象共享,静态数据成员具有静态生存期
  • 必须在类外定义和初始化,用(::)来指明所属的类

class 类名称
{
    // 在关键字public后面声明的是共有类型成员,类与外部的接口,任何外部函数都可以访问共有类型数据和函数。类(class)中只有声明,定义在外部定义
    public:
        共有成员(外部接口)
    //在关键字private后面声明的是私有类型成员,只允许本类中的函数访问,而类外部的任何函数都不能访问。
    //如果紧跟在类名称的后面(在前面的class后面的类名称后,即大括号里面声明的第一个)声明私有成员,则关键字private可以省略。
    private:
        私有成员
    //与private相似,其差别表现在继承与派生时对派生类的影响不同。
    protected:
        保护型成员
};

类的成员函数

  • 在类中声明函数原型;
  • 可以在类外给出函数体实现,并在函数名前使用类名加以限定;
  • 也可以直接在类中给出函数体,形成内联成员函数;
  • 允许声明重载函数和带默认参数值的函数。

内联成员函数

  • 为了提高运行时的效率,对于简单的函数可以声明为内联形式。
  • 内联函数体中不要有复杂结构(如循环语句和switch语句)。
  • 在类中声明内联函数的方式
    -1.将函数体放在类的声明中
    -2.使用inline关键字
#include <iostream>
using namespace std;

class Clock {
public:
	void setTime(int newH = 0, int newM = 0, int newS = 0);
	void showTime();
private:
	int hour, minute, second;
};

void Clock::setTime(int newH, int newM, int newS) {
	hour = newH;
	minute = newM;
	second = newS;
}

void Clock::showTime() {
	cout << hour << minute << second;
}

int main()
{
	Clock myClock;
	myClock.setTime(8, 30, 30);
	myClock.showTime();

	return 0;
}

// 两种方法,两种定义方式。
class Point
{
public:
	void Init(int initX, int initY)
	{
		X = initX;
		Y = initY;
	}
	int getX() { return X; }
	int GetY() { return Y; }
private:
	int X, Y;
};

class Point
{
public:
	void Init(int initX, int initY);
	int GetX();
	int GetY();
private:
	int X, Y;
};
inline void Point::Init(int initX, int initY)
{
	X = initX;
	Y = initY;
}
inline int Point::GetX()
{
	return X;
}
inline int Point::GetY()
{
	return Y;
}

构造函数

在对象被创建时使用特定的值构造对象,或者将对象初始化为一个特定的初始状态

  • 函数名与类名相同
  • 不能定义返回值类型,也不能有return语句,但也不能用void
  • 不能人为调用,只能系统调用
  • 可以有形式参数,也可以没有形式参数
  • 可以是内联函数
  • 可以重载
  • 可以带默认参数值

默认构造函数
调用时可以不需要实参的构造函数

  • 参数表为空的构造函数

  • 全部参数都有默认值的构造函数

  • 构造函数调用顺序:先调用内嵌对象的构造函数(按内嵌时的声明顺序,先声明者先构造)。然后调用本类的构造函数。(析构函数的调用顺序相反)

  • 若调用默认构造函数(即无形参的),则内嵌对象的初始化也将调用相应的默认构造函数。

构造函数例子
#include <iostream>
using namespace std;

class Clock {
public:
    Clock(int newH, int newM, int newS); // 构造函数(函数名和类名相同)。
    Clock(); // 默认构造函数
    void setTime(int newH = 0, int newM = 0, int newS = 0);
    void showTime();
private:
    int hour, minute, second;
};

// 构造函数的实现:(不能规定返回类型return)
Clock::Clock(int newH, int newM, int newS) : // 初始化列表
    hour(newH), minute(newM), second(newS) {}

Clock::Clock() :hour(0), minute(0), second(0) {} // 默认构造函数

void Clock::setTime(int newH, int newM, int newS) {
    hour = newH;
    minute = newM;
    second = newS;
}

void Clock::showTime() {
    cout << hour << minute << second << endl;
}

int main()
{
    Clock c(8, 10, 0); // 自动调用构造函数
    Clock c2;
    c.showTime();
    c2.showTime();

    return 0;
}

委托构造函数

委托构造函数使用类的其他构造函数执行初始化过程。

例如

Clock(int newH, int newM, int newS):
	hour(newH), minute(newM), second(newS) {}
Clock::Clock() : hour(0), minute(0), second(0) {}

Clock(int newH, int newM, int newS):
	hour(newH), minute(newM), second(newS) {}
Clock: Clock(0, 0, 0) {}

复制构造函数定义(或者是拷贝构造函数)

复制构造函数是一种特殊的构造函数,其形参为本类对象引用。作用是用一个已存在的对象去初始化同类型的新对象。

复制构造函数被调用的三种情况
  • 当用类的一个对象去初始化该类的另一个对象时
int main()
{
    Point a(1, 2);
    Point b(a);
    Point c = a; // 这两句表达的意思相同。
}
  • 如果函数的形参是类的对象,调用函数时,实现形参和实参结合时。
void f(Point p)
{
	cout << p.getX() << endl;
}
int main()
{
	Point a(1, 2);
	f(a); // 函数的形参是类的对象,调用函数时,调用!
	return 0;
}
// 只有把对象用值传递时,才会调用复制构造函数,如果传递引用,则不会调用复制构造函数。传递较大的对象时,传递引用比传值的效率高很多。
  • 如果函数的返回值是类的对象,函数执行完成返回调用者时。
Point g() {
	Point a(1, 2);
	return a; // 函数的返回值是类的对象,返回函数值时,调用复制构造函数。
}
int main()
{
	Point b;
	b = g();
	return 0;
}
class 类名{
public:
    类名(形参); // 构造函数
    类名(const 类名&amp;amp;对象名); // 复制构造函数
    //...
};
类名::类(const 类名&amp;amp;对象名) // 复制构造函数的实现
{ 函数体 }
#include <iostream>
using namespace std;

class Point {
public:
	Point(int xx = 0, int yy = 0) {	// 构造函数
		x = xx;
		y = yy;
	}
	Point(Point& p); // 拷贝构造函数
	int getX() { return x; }
	int getY() { return y; }
private: // 私有数据
	int x, y;
};

// 成员函数的实现
Point::Point(Point&amp;amp; p) {
	x = p.x;
	y = p.y;
	cout << "Calling the copy constructor" << endl;
}

// 形参为Point类对象的函数
void fun1(Point p) {
	cout << p.getX() << endl;
}

// 返回值为Point类对象的函数
Point fun2() {
	Point a(1, 2);
	return a;
}

int main() {
	Point a; // 第一个对象A
	Point b = a; // 情况一,用A初始化B。第一次调用拷贝构造函数
	cout << b.getX() << endl;
	fun1(b); // 情况二,对象B作为fun1的实参。第二次调用拷贝构造函数
	b = fun2(); // 情况三,函数的返回值是类对象,函数返回时,调用拷贝构造函数
	cout << b.getX() << endl;
	return 0;
}

析构函数

  • 析构函数名也应与类名相同,只是在函数名前面加一个位取反符~,以区别于构造函数。
  • 它不能带任何参数,也没有返回值(包括void类型)。
  • 只能有一个析构函数,不能重载。
  • 如果用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数(即使自定义了析构函数,编译器也总是会为我们合成一个析构函数,并且如果自定义了析构函数,编译器在执行时会先调用自定义的析构函数再调用合成的析构函数),它也不进行任何操作。所以许多简单的类中没有用显式的析构函数。
#include <iostream>
using namespace std;

class Point {
public:
	Point(int xx, int yy);
	~Point();
	// 其他函数...
private:
	int x, y;
};
Point::Point(int xx, int yy)
{
	x = xx;
	y = yy;
}
Point::~Point() {
}
// 其他略...

类的组合

  • 类中的成员是另一个类的对象
  • 可以在已有抽象的基础上实现更复杂的抽象
#include <iostream>
using namespace std;

class Piont
{
private:
	float x, y;// 点的坐标
public:
	Point(float h, float v); // 构造函数
	float GetX(void);
	float GetY(void);
	void Draw(void); // 在x,y处画点
};

class Line
{
private:
	Point p1, p2; // 线段的两个端点
public:
	Line(Point a, Point b); // 构造函数
	void Draw(void); // 画出线段
};

类组合的构造函数的设计

原则:不仅要负责对本类中的基本类型成员赋初值,也要对对象成员初始化。
声明形式:
类名::类名(对象成员所需的形参,本类成员形参)
:对象1(参数),对象2(参数),......
{ 本类初始化 }

#include <math.h>
#include <iostream>
using namespace std;

class Point { // Point类定义
public:
	Point(int xx = 0, int yy = 0) {
		x = xx;
		y = yy;
	}
	Point(Point& p); // 拷贝构造函数
	int getX() { return x; }
	int getY() { return y; }
private:
	int x, y;
};

Point::Point(Point& p) {
	x = p.x;
	y = p.y;
	cout << "Calling the copy constructor of Point" << endl;
}

// 类的组合
class Line { // Line的定义
public:
	Line(Point xp1, Point xp2);
	Line(Line& l);
	double getLen() { return len; }
private:
	Point p1, p2;
	double len;
};

Line::Line(Point xp1, Point xp2) :p1(xp1), p2(xp2) { // 相当于p1 = xp1。
	cout << "Calling constructor of Line" << endl;
	// 把后面的强制转化成double类型(静态转换)
	double x = static_cast <double> (p1.getX() - p2.getX());
	double y = static_cast <double> (p1.getY() - p2.getY());
	len = sqrt(x * x + y * y);
}

Line::Line(Line& l) :p1(l.p1), p2(l.p2) {
	cout << "Calling the copy constructor of Line" << endl;
	len = l.len;
}

int main()
{
	Point myp1(1, 1), myp2(4, 5);
	Line line(myp1, myp2); // 1,myp1给xp1,然后到了Point;2,从右到左,先myp2
	Line line2(line);
	cout << "The length of the line is :";
	cout << line.getLen() << endl;
	cout << "The length of the line2 is :";
	cout << line2.getLen() << endl;

	return 0;
}

构造组合类对象时的初始化次序

  • 首先对构造函数初始化列表中列出的成员(包括基本类型成员和对象成员)进行初始化,初始化次序是成员在类体中定义的次序
    成员对象构造函数调用顺序:按对象成员的定义顺序,先声明者先构造。
    初始化成员列表中未出现的成员对象,调用默认构造函数(即无形参的)初始化
  • 处理完初始化列表后,在执行构造函数的函数体。

前向引用声明

  • 类要先声明,后使用
  • 如果需要在某个类的声明之前,引用该类,则应进行前向引用声明
  • 前向引用声明只为程序引入一个标识符,但具体声明在其他地方
class B; // 前向引用声明
class A {
public:
	void f(B, b);
};
class B {
public:
	void g(A, a);
};
注意事项
  • 在提供一个完整的类声明之前,不能声明该类的对象,也不能在内联成员函数中使用该类的对象
  • 当使用前向引用声明时,只能使用被声明的符号,而不能涉及类的任何细节。

前向引用声明并不是万能的。需要注意的是,尽管使用了前向引用声明,但是在提供一个完整的类声明之前,不能声明该类的对象,也不能在内联成员函数中使用该类的对象。例如:

class Fred; // 前向引用声明
class Barney {
    Fred x; // 错误:类Fred的声明尚不完善
};
class Fred {
    Barney y;
}
class Fred;
class Barney{
    Fred *x; // 正确。。。
};
class Fred{
    Barney y;
};
class Fred; // 前向引用声明

class Barney {
public:
    void method()
    {
    x << yabbaDabbaDo(); // 错误: Fred类的对象在定义之前被使用
    }
private:
    Fred* x; // 正确,经过前向引用声明,可以声明Fred类的对象指针
};
class Fred{
public:
    void tabbaDabbaDo();
private:
    Barney * y;
};

UML:
事情(Things)
关系(Relationships)
图(Diagrams)

枚举类定义

enum class 枚举类型名: 底层类型{枚举值列表};

枚举类的优势

  1. 强作用域,其作用域限制在枚举类中;
  • 例:使用Type的枚举值General
    Type::General
  1. 转换限制,枚举类对象不可以与整形隐式地相互转换;
  2. 可以指定底层类型
  • 例:enum class Type: char{General, Light, Medium, Heavy};
    这个就说char类型的,不写表示int
#include <iostream>
using namespace std;

enum class Side {Right, Left};
enum class Thing{Wrong, Right}; // 不冲突

int main()
{
	Side s = Side::Right;
	Thing w = Thing::Wrong;
	cout << (s == w) << endl; // 编译错误,无法直接比较不同枚举类
	return 0;
}

实例:

#include <iostream>
using namespace std;

enum CPU_Rank { P1 = 1, P2, P3, P4, P5, P6, P7 };

class CPU {
private:
	CPU_Rank rank;
	int frequency;
	float voltage;
public:
	CPU(CPU_Rank r, int f, float v)
	{
		rank = r;
		frequency = f;
		voltage = v;
		cout << "构造函数CPU!" << endl;
	}

	CPU(CPU& c)
	{
		rank = c.rank;
		frequency = c.frequency;
		voltage = c.voltage;

		cout << "拷贝了构造函数CPU!" << endl;
	}

	~CPU() { cout << "析构函数CPU!" << endl; }

	CPU_Rank GetRank() const { return rank; }
	int GetFrequency() const { return frequency; }
	float GetVoltage() const { return voltage; }

	void SetRank(CPU_Rank r) { rank = r; }
	void SetFrequency(int f) { frequency = f; }
	void SetVoltage(float v) { voltage = v; }

	void Run() { cout << "CPU starts to run!" << endl; }
	void Stop() { cout << "CPU is stoped!" << endl; }
};

enum RAM_Type { DDR2 = 2, DDR3, DDR4 };
class RAM {
private:
	enum RAM_Type type;
	unsigned int frequency; // MHz
	unsigned int size; // GB
public:
	RAM(RAM_Type t, unsigned int f, unsigned int s)
	{
		type = t;
		frequency = f;
		size = s;
		cout << "构造函数RAM!" << endl;
	}

	RAM(RAM& r)
	{
		type = r.type;
		frequency = r.frequency;
		size = r.size;

		cout << "拷贝了构造函数RAM!" << endl;
	}

	~RAM() { cout << "析构函数RAM!" << endl; }

	RAM_Type GetType() const { return type; }
	unsigned int GetFrequency() const { return frequency; }
	unsigned int GetSize() const { return size; }

	void SetType(RAM_Type t) { type = t; }
	void SetFrequency(unsigned int f) { frequency = f; }
	void SetSize(unsigned int s) { size = s; }

	void Run() { cout << "RAM starts to run!" << endl; }
	void Stop() { cout << "RAM is stoped!" << endl; }
};

enum CDROM_Interface { SATA, USB };
enum CDROM_Install_type { external, built_in };
class CD_ROM {
private:
	enum CDROM_Interface interface_type;
	unsigned int cache_size; // MB
	CDROM_Install_type install_type;
public:
	CD_ROM(CDROM_Interface i, unsigned int s, CDROM_Install_type it)
	{
		interface_type = i;
		cache_size = s;
		install_type = it;
		cout << "构造函数CD_RAM!" << endl;
	}

	CD_ROM(CD_ROM& cd)
	{
		interface_type = cd.interface_type;
		cache_size = cd.cache_size;
		install_type = cd.install_type;

		cout << "拷贝了构造函数CD_RAM!" << endl;
	}
	~CD_ROM() { cout << "析构函数CD_ROM!" << endl; }

	CDROM_Interface GetInterfaceType() const { return interface_type; }
	unsigned int GetSize() const { return cache_size; }
	CDROM_Install_type GetStallType() const { return install_type; }

	void SetType(CDROM_Interface i) { interface_type = i; }
	void SetFrequency(unsigned int s) { cache_size = s; }
	void SetStallType(CDROM_Install_type it) { install_type = it; }

	void Run() { cout << "CDROM starts to run!" << endl; }
	void Stop() { cout << "CDROM is stoped!" << endl; }
};

class COMPUTER {
private:
	CPU my_cpu;
	RAM my_ram;
	CD_ROM my_cdrom;
	unsigned int storage_size; // GB
	unsigned int bandwidth; // MB
public:
	COMPUTER(CPU c, RAM r, CD_ROM cd, unsigned int s, unsigned int b);

	~COMPUTER() { cout << "析构COMPUTER!" << endl; }
	void Run() {
		my_cpu.Run();
		my_ram.Run();
		my_cdrom.Run();
		cout << "COMPUTER开始运行!" << endl;
	}

	void Stop()
	{
		my_cpu.Stop();
		my_ram.Stop();
		my_cdrom.Stop();
		cout << "COMPUTER开始关机!" << endl;
	}
};
COMPUTER::COMPUTER(CPU c, RAM r, CD_ROM cd, unsigned int s, unsigned int b) :my_cpu(c), my_ram(r), my_cdrom(cd)
{
	storage_size = s;
	bandwidth = b;

	cout << "构造了一个COMPUTER!" << endl;
}

int main()
{
	CPU a(P4, 300, 2.4);
	a.Run();
	a.Stop();
	cout << "*********************************\n";

	RAM b(DDR3, 1600, 8);
	b.Run();
	b.Stop();
	cout << "*********************************\n";

	CD_ROM c(SATA, 2, built_in);
	c.Run();
	c.Stop();
	cout << "*********************************\n";

	COMPUTER my_computer(a, b, c, 128, 10);
	cout << "*********************************\n";

	my_computer.Run();
	my_computer.Stop();
	cout << "*********************************\n";

	return 0;
}
/*
构造函数CPU!
CPU starts to run!
CPU is stoped!
*********************************
构造函数RAM!
RAM starts to run!
RAM is stoped!
*********************************
构造函数CD_RAM!
CDROM starts to run!
CDROM is stoped!
*********************************
拷贝了构造函数CD_RAM!
拷贝了构造函数RAM!
拷贝了构造函数CPU!
拷贝了构造函数CPU!
拷贝了构造函数RAM!
拷贝了构造函数CD_RAM!
构造了一个COMPUTER!
析构函数CPU!
析构函数RAM!
析构函数CD_ROM!
*********************************
CPU starts to run!
RAM starts to run!
CDROM starts to run!
COMPUTER开始运行!
CPU is stoped!
RAM is stoped!
CDROM is stoped!
COMPUTER开始关机!
*********************************
析构COMPUTER!
析构函数CD_ROM!
析构函数RAM!
析构函数CPU!
析构函数CD_ROM!
析构函数RAM!
析构函数CPU!
*/
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值