私人班级成员没有完全封装?

时间:2013-03-08 21:13:05

标签: c++ encapsulation

这是Instance-level encapsulation with C++的后续帖子。

我已经定义了一个类并从该类中创建了两个对象。

#include <iostream>
#include <ctime>
#include <string>

using namespace std;

class timeclass {
  private:
  string date;

  time_t gmrawtime, rawtime;
  struct tm * timeinfo;
  char file_date[9];

  void tm_init(int);

public:
  timeclass(int);
  void print_date();
};

void timeclass::tm_init(int y) {
  timeinfo = gmtime(&rawtime);
  timeinfo->tm_year = y - 1900; // timeinfo->tm_year holds number of years since 1900
  timeinfo->tm_mon = 0;
  timeinfo->tm_mday = 1;
  timeinfo->tm_hour = 0;
  timeinfo->tm_min= 0;
  timeinfo->tm_sec= 0;
}

timeclass::timeclass(int y) {
  timeclass::tm_init(y);
  gmrawtime = mktime(timeinfo) - timezone; 
}

void timeclass::print_date() {
  strftime(file_date,9,"%Y%m%d",timeinfo);

  date = string(file_date);
  cout<<date<<endl;
}

/* -----------------------------------------------------------------------*/

int main()
{
  timeclass time1(1991); 
  timeclass time2(1992); 

  time1.print_date(); // Prints 19920101, despite being initialized with 1991
  time2.print_date(); // Prints 19920101, as expected

  return 0;
}

此示例是从我的主程序切片和切块的日期计数器的一部分,但它说明了我的观点。我希望为类的每个实例(time1和time2)运行一个日期计数器,但看起来我构造了time2对象,我认为在time1中封装的'timeinfo'变量被time2构造函数覆盖。

我知道C ++仅支持类级封装,我想知道我的问题是否是因为同一类的成员可以访问彼此的私有成员。有没有解决方法,所以我可以实现我想做的事情?谢谢, 泰勒

3 个答案:

答案 0 :(得分:5)

gmtime()localtime()ctime()asctime()返回指向静态数据的指针。因此,后续调用可能会覆盖先前调用所写的信息。这也意味着这些调用不是线程安全的,尽管在这种情况下不涉及多个线程。

其他答案为此限制提供了可能的解决方法。

答案 1 :(得分:2)

您实际上并不想要gmtime()(请参阅Shafik's answer)。您只需要std::tm即可修改:

void timeclass::tm_init(int y) {
  timeinfo = new std::tm;
  timeinfo->tm_year = y - 1900;
  timeinfo->tm_mon = 0;
  timeinfo->tm_mday = 1;
  timeinfo->tm_hour = 0;
  timeinfo->tm_min= 0;
  timeinfo->tm_sec= 0;
}

正如Shafik已经写过的,您的问题是您指向的许多std::tm方法使用的内部静态*time()。因此,只需创建自己的std::tm,甚至更简单,将其用作成员而不是指针:

class timeclass {
  private:
  std::tm timeinfo;
  /* rest stays the same */
};

void timeclass::tm_init(int y) {
  timeinfo = *std::gmtime(&rawtime); // if you need gmtime
  timeinfo.tm_year = y - 1900;
  timeinfo.tm_mon = 0;
  timeinfo.tm_mday = 1;
  timeinfo.tm_hour = 0;
  timeinfo.tm_min= 0;
  timeinfo.tm_sec= 0;
}

答案 2 :(得分:0)

正如其他人所指出的那样,问题是您使用的功能会返回全局数据。所以你的问题已经过了一步。

但是,正如您所指出的,C ++封装在类级别而不是对象级别,因此任何对象都可以修改同一类的任何其他对象的私有数据。

你可以通过仅使用抽象类作为参数和类成员来解决这个问题:

class Time {
public:
    virtual void setYear(int year) = 0;
    virtual void printDate() = 0;
    virtual void subtract(Time& otherTime) = 0;   
};