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 类名&对象名); // 复制构造函数
    //...
};
类名::类(const 类名&对象名) // 复制构造函数的实现
{ 函数体 }
#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& 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 收藏 评论
分享
牛客网
牛客企业服务