09. 私有和公开

私有、受保护和公开是什么意思?

在高斯类声明中,mu 和 sigma2 变量被标记为私有的,而其余的变量和函数被标记为公开的。以下一个类声明,供参考:

class Gaussian
{
    private:
        float mu, sigma2;

    public:

        //构造函数
        Gaussian ();
        Gaussian (float, float);

        //改变均差和标准偏差的值 
        void setMu(float);
        void setSigma2(float);

        //输出均差和标准偏差的值
        float getMu();
        float getSigma2();

        //待评估函数 
        float evaluate (float);
        Gaussian multiply (Gaussian);
        Gaussian add (Gaussian);
};

关键字 private public 决定了程序的哪一部分可以访问变量和函数。如果一个变量或函数是
private ,那么只有这个类本身才能访问这些变量和函数。

另一方面,任何标有 public 的内容都可以在类外访问;例如,当你实例化一个对象时,你的程序将能够使用 set 和 get 函数以及 evaluate、multiply 和 add 函数;但是,你的程序无法直接访问 mu 和 sigma2 变量。

还有另外一个名为 protected 的关键字,上例中没有使用。基本上, protected 类和变量可以被任何子类访问。例如,你写了一个 Vehicle 类后,可以在写一个 Car 类、一个 Van 类和一个 Truck 类,它们都可以继承更通用的 Vehicle 类。Vehicle 类中的任何受保护的变量都可以在子类中访问。

下面是 Gaussian 类的另一个例子,但是 mu 和 sigma2 已经公开。请注意,getMu、getSigma2、setMu 和 setSigma2 函数已经没有必要,因为对象可以直接访问这些变量。

Start Quiz:

#include <iostream>
#include "gaussian.h"

int main ()
{

	Gaussian mygaussian(30.0,20.0);
	Gaussian othergaussian(10.0,30.0);
	
	std::cout << "average " << mygaussian.mu << std::endl;
	
	std::cout << "evaluation " << mygaussian.evaluate(15.0) << std::endl;

	std::cout << "mul results sigma " << mygaussian.mul(othergaussian).sigma2 << std::endl;
	std::cout << "mul results average " << mygaussian.mul(othergaussian).mu << std::endl;

	std::cout << "add results sigma " << mygaussian.add(othergaussian).sigma2 << std::endl;
	std::cout << "add results average " << mygaussian.add(othergaussian).mu << std::endl;

	std::cout << "average " << mygaussian.mu << std::endl;
    mygaussian.mu = 25;
    std::cout << "average " << mygaussian.mu << std::endl;
     
	return 0;
}
#include <math.h>       /* sqrt, exp */
#include "gaussian.h"

Gaussian::Gaussian() {
	mu = 0;
	sigma2 = 1;	
}

Gaussian::Gaussian (float average, float sigma) {
	mu = average;
	sigma2 = sigma;
}

float Gaussian::evaluate(float x) {
	float coefficient;
	float exponential;

	coefficient = 1.0 / sqrt (2.0 * M_PI * sigma2);
	exponential = exp ( pow (-0.5 * (x - mu), 2) / sigma2 );
	return coefficient * exponential;
}

Gaussian Gaussian::mul(Gaussian other) {
	float denominator;
	float numerator;
	float new_mu;
	float new_var;

	denominator = sigma2 + other.sigma2;
	numerator = mu * other.sigma2 + other.mu * sigma2;
	new_mu = numerator / denominator;

	new_var = 1.0 / ( (1.0 / sigma2) + (1.0 / other.sigma2) );

	return Gaussian(new_mu, new_var);
}

Gaussian Gaussian::add(Gaussian other) {

	float new_mu;
	float new_sigma2;

	new_mu = mu + other.mu;
	new_sigma2 = sigma2 + other.sigma2;

	return Gaussian(new_mu, new_sigma2);
}
class Gaussian
{

	public:

		float mu, sigma2;
		
		// constructor functions
		Gaussian ();
		Gaussian (float, float);

		// functions to evaluate 
		float evaluate (float);
		Gaussian mul (Gaussian);
		Gaussian add (Gaussian);
};

为什么保持私有

默认情况下,C++ 中所有的类变量和函数都是私有的。这意味着,当你在类声明的顶部声明私有变量和函数时,不用标记 private

class Gaussian
{
    float mu, sigma2;

    public:

        // constructor functions
        Gaussian ();
        Gaussian (float, float);

        //改变均差和标准偏差的值
        void setMu(float);
        void setSigma2(float);

        //输出均差和标准偏差的值
        float getMu();
        float getSigma2();

        //待评估函数
        float evaluate (float);
        Gaussian mul (Gaussian);
        Gaussian add (Gaussian);
};

因此,C++ 鼓励你把所有东西都设为私有,除非你有充分的理由。例如,将 mu 和 sigma2 设为私有后,你已经分离了 mu 和 sigma2 的实现方式和访问方式。

如果你的类计算 mu 和 sigma2 的方式发生了变化,会发生什么?如果这些变量是公开的,那么任何使用你的类的代码都可能会被破坏。当 mu 和 sigma2 公开时,一个程序可以直接改变 mu 和 sigma 的值,代码如下:

    mygaussian.mu = 25;

但如果 mu 和 sigma2 是私有的,程序必须使用这样的代码:

mygaussian.setMu(25)

如果你需要改变 mu 变量的实现,在私有的情况下,现有代码就不太可能被破坏。使用 Gaussian 类的程序不需要知道 mu 是如何实现的,只要程序能够得到 mu 值并且改变 mu 值即可。