Featured image of post C++面向对象高级开发-Static关键字、类模板函数模板及命名空间

C++面向对象高级开发-Static关键字、类模板函数模板及命名空间

static与this指针, 单例设计模式, 类模板与函数模板, 命名空间, 其他细节

C++面向对象高级开发-static关键字、类模板函数模板及命名空间

Notes

  • static与this指针
  • 单例设计模式
  • 类模板与函数模板
  • 命名空间
  • 其他细节

static与this指针

Complex复数类创建三个对象,若以非静态方式创建对象,则代码可写为:

Complex c1, c2, c3;
std::cout << c1.real() << std::endl;
std::cout << c2.real() << std::endl;
std::cout << c3.real() << std::endl;

c1调用real,所以c1是real()的this指针,故c1的地址就成为real的this指针,使用this指针传入,与上方代码具有同等效力的代码如下:

Complex c1, c2, c3;
std::cout << Complex::real(&c1) << std::endl;
std::cout << Complex::real(&c2) << std::endl;
std::cout << Complex::real(&c3) << std::endl;

调用相同的函数传入不同的地址可以处理到不同的数据。在无static关键字时,成员函数只有一份,处理多个非static对象,就是使用this指针传递给函数处理数据。

在对象前增加static关键字,static数据在内存中单独存在,不属于对象。static函数与成员函数一致,仍然只有一份。static函数特征与一般成员函数的特征差别在于static函数无this指针,所以static函数只能处理static数据。对于任何的银行账户,存款利率唯一,可考虑使用static处理,代码如下:

class Account {
public:
    static double m_rate;
    static void set_rate(const double& x) {m_rate = x;}
};

double Account::m_rate = 8.0;

int main(int argc, const char* argv[]) {
    Account::set_rate(5.0); //通过class name调用
    Account a;
    a.set_rate(7.0);        //通过object调用
    return 0;
}

设计规范9:

静态数据在class外设初值定义

调用static函数的方式有两种:

  • 通过object调用
  • 通过class name调用

单例设计模式Singleton

将构造函数放在private中,class只产生一个对象时,可使用static关键字处理唯一对象。

class A {
public:
    static A& getInstance();
    setup() {...}
private:
    A();
    A(const A& rhs);
    ...
};

A& A::getInstance() {
    static A a;
    return a;
}

static A a;写入getInstance函数中,只有getInstance被访问,对象a才会创建,直接写入private区,可能导致空间浪费。

cout继承自ostream,对各种类型的数据均有操作符重载,所以cout可以输出各种类型的数据。

类模板与函数模板

类模板

当设计的class中数据类型不确定或可变更时,可用template类模板变更。编译器读取到语句complex<double> c1(2.5, 1.5)后,会将class类中所有的T全部替换为double。

函数模板

设有3个stone类型的对象,取前两个里面最小的赋值给第三个。考虑设计取最小值函数,传入参数类型与函数功能无关。可引入函数模板完成对任意参数类型的支持。其中template <class T> 与类模板中template <typename T>原理相同。 函数模板与类模板的不同之处是类模板在使用时要传入typename参数,如complex<int> c1(1,2);,而函数模板在执行至语句如r3 = min(r1, r2);时,编译器会对函数模板进行实参类型推导。例子中获得T为stone类型,stone类型进行比较需要操作符重载。使用函数模板进行设计是较好的设计方法。操作符重载需要类设计者完善。C++标准库中算法大部分均采用函数模板设计。

命名空间 namespace

命名空间可以通过using directive方式与using declartion方式使用。using directive方式为全局开放模式,使用using语句后,该命名空间的内容可直接使用,不需通过namespace::variable的方式使用,代码如下。

#include <iostream>

using namespace std;

int main(int argc, const char * argv[]) {
    cin << ...;
    cout << ...;
}

using declartion方式为按条声明使用。即一行只解锁一个命名空间中的对象,代码如下。

#include <iostream>

using std::cout;

int main(int argc, const char * argv[]) {
    std::cin << ...;
    cout << ...;
}

其他细节

其他细节

operator type() const;为转换函数。可理解为重载强制类型转换操作符。如编译器可将语句operator int()类对象转换为int型数据。 explicit complex():...语句中explicit关键字可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生。声明为explicit的构造函数不能在隐式转换中使用,只能显式调用。 object可变为指针类似或函数类似对象。 其余细节后续笔记中会补充。