2012-04-20 30 views
1

当谈到创建类时,我被告知没有公共数据成员。这很好,我明白为什么,但这是我的问题。我有一个我在类中使用的结构(线性链表)。我真的很想将其中一个struct字段(一个数组)初始化为NULL,这样我就可以检查客户端是否传递了有效的结构,而不是未经初始化的那些充满垃圾值的结构。我意识到C++不会让我在struct声明中设置一个默认值,所以我如何保护客户端不给我垃圾?结构或类,公共数据呢?

struct task { 
    char *description; 
    char *name; 
    float time_remaining; 
    float time_spent; 
}; 

然后在我的课,我试图做一些事情,如:

//I am making a copy of "to_add" and storing it in the LLL 
int list::add_to_list(const task & to_add) 
{ /.../ } 

我不希望用户添加一堆未初始化“任务的”到链表...什么去做?当我将该结构转换为类并将数据成员移动到私有时,我尝试访问数据成员以制作它们的副本。我非常小心,不要做任何事情来影响var的值,但是我无法摆脱编译器给我提供有关“错误:将'const task''作为'char'task :: get_comp_name ()'丢弃限定符[-fpermissive]“(”get_comp_name“)是我确定没有编辑任何值的获取者之一,只是传给我一个副本)请在拍摄自己之前帮助我。在脸上。

+0

我无法理解问题。没有公共数据成员意味着访问可能对“外部”世界“有趣”的数据的唯一方式是通过吸气剂,如果需要设置它们,则必须通过一个setter来完成。当一个实例被创建时,你可以将你的私有成员初始化为任何你想要的。任何从外部作为方法参数传递的东西都可能是不安全的,但这是“正常的”,我不明白你是如何将它与非公开数据要求相耦合的,它们在我看来有两个不同的“事实”。你能解释得更好吗? – ShinTakezou 2012-04-20 05:42:12

+0

错误是因为你没有声明函数const。如果你真的想提供访问者而不是公共数据,那么getter应该像'char const * get_comp_name()const;'那样。 – 2012-04-20 06:25:51

回答

4

在C++中,一个struct和一个class除了访问控制外都是一样的。所以结构对成员和继承的默认访问是公共的,而类'一个是私有的。所以你可以给你的struct一个defult构造函数和其他的来初始化它。

struct task { 
    task() : desctiption(0), name(0), time_remaining(0.), time_spent(0.) {} 
    char *description; 
    char *name; 
    float time_remaining; 
    float time_spent; 
}; 

添加构造函数的一个副作用是该结构不再是聚合。这对你来说可能是也可能不是问题。

在C++ 11,你还可以在声明的时候初始化成员:

struct task { 
    char *description{nullptr}; 
    char *name{nullptr}; 
    float time_remaining{0}; 
    float time_spent{0}; 
}; 

这就地初始化接受type x = y语法也和争论少{}初始化结果值初始化为,这导致对初始类型的零初始化为,因此可以省略示例中的参数。

+0

+1。顺便说一下,'char * name {}'就足够了。同样,'float time_spent {}'。 [更多这里](http://stackoverflow.com/questions/10147264/braces-around-string-literal-in-char-array-declaration-valid-e-g-char-s/10147335#10147335)。 – Nawaz 2012-04-20 05:44:36

+0

@Nawaz确实,我会添加一些东西。 – juanchopanza 2012-04-20 05:48:31

+0

就是这样!该死的我爱你们。这么多聪明的人在这里。万分感谢! – MCP 2012-04-20 05:50:27

1

的结构实现一个构造函数:

struct task { 
    task() : description(0), name(0), time_remaining(0), time_spent(0) {} 
    char *description; 
    char *name; 
    float time_remaining; 
    float time_spent; 
}; 

类和C++中的结构之间的唯一区别是它的成员的默认可访问性。

+0

另一个区别是默认继承,这是公共的结构和私人的类。 – juanchopanza 2012-04-20 05:47:13

+0

@Andreas:在C++中* visibility *和* accessibility *有区别。你应该写的是,*可访问性*,**不** *可见性*。 – Nawaz 2012-04-20 05:48:26

2

这里有几个问题。

公开还是不公开?

公共属性看起来很方便,但通常会在最不经意的时候回来咬你。我已经怀疑time_remainingtime_spent有问题了:我想这两个都是在相同时刻修改过的,不是吗?

默认情况下,变量属性应该是private,使类别可以执行不变量作为这样time_remaining + time_spent在整个任务的寿命的常数。

对于常量属性,它可以是public,它们在不变量中的作用无论如何都是在构造函数中一次性完成的。

但奇怪的错误消息?

这是因为你缺乏一个很好的教程或书籍。手头的问题很简单:这是一个与const相关的问题。

A const对象只能通过const引用或值传递给函数/方法,并且只能调用const方法。在你的情况下,name()方法的正确声明在方法名称后面应该有一个const限定符。

把它完全

而且在std::string扔,因为它是如此容易操纵。

class Task { 
public: 
    Task(): time_remaining(0), time_spent(0) {} 
    Task(std::string name, std::string desc, float duration): 
     _name(name), _desc(desc), _time_remaining(duration), _time_spent(0) {} 

    // Accessors 
    std::string const& name() const { return _name; } 
    std::string const& description() const { return _desc; } 
    float time_remaining() const { return _time_remaining; } 
    float time_spent() const { return _time_spent; } 

    // Modifiers 
    void spend(float duration) { 
     _time_remaining -= duration; 
     _time_spent += duration; 
    } 

private: 
    std::string _name, _desc; 
    float _time_remaining, _time_spent; 
}; // class Task 

注:它可能是有益的检查传递给spend方法duration并不优于_time_remaining属性,否则你花更多的比你...

+0

这看起来像一个伟大的宣言!所以到了这一点。就访问者而言:因为你正在使用字符串,那些访问器只是返回一个副本,对吧?如果你正在使用一个数组(如指针)呢?请问函数名后的“const”是否足以让一个访问/创建数组的独立副本? – MCP 2012-04-20 15:20:18

+1

@MCP:不是,它们正在返回'std :: string const&',它是对字符串的const引用。如果调用者写入'std :: string const&name = t.name();'她得到一个const引用,如果她写入'std :: string const name = t.name();'(巧妙地缺少' ')她得到一个'const'值(而不是'const'在后一种情况下是可选的)。方法上的'const'意味着你不能改变类的内部属性。如果这个类持有一个指针,那么指针本身不能被改变,但是它指向的对象可能会被改变,如果它不是'const'限定的。 – 2012-04-20 15:47:09

+0

@MCP:你应该在这个网站或教程上寻找问题来理解'const'-ness。如果解释得当,这是一个很简单的话题,但如果不是这样,它可能会变得非常混乱。特别是因为它不仅仅是技术性的,而且还可以用于逻辑“常量”,通常更有用,这需要一些关于概念的经验(以及开始的准则)。 – 2012-04-20 15:48:55