如何防止公共成员被其派生类继承?就像,如果我有这个:
class Person {
public:
enum { MALE, FEMALE, BOTH };
Person(std::string name, int gender)
: _name(name)
{
switch (gender) { /* processing here */ }
}
protected:
std::string _name;
};
class Male : public Person {
public:
Male(std::string name)
: _name(name, 0) { }
};
我想这样做的原因是,我希望能够用以下内容实例化一个人类:
Person person("The Name", Person::MALE);
但是,因为enum
是公开的,所以也可以使用:
Male::MALE
Male::FEMALE
Male::BOTH
再也没有任何意义了。如何防止派生类能够访问这些枚举值,但是可以从基类中公开它?
答案 0 :(得分:2)
如果您坚持将enum
保留在基类中,则可以将enum
放在受保护的部分中。
class Person {
protected:
enum Gender { MALE, FEMALE, BOTH };
Person(std::string name, Gender gender)
: _name(name)
{
switch (gender) { /* processing here */ }
}
std::string _name;
public:
virtual ~Person () {}
//...
};
公开派生自Person
的类仍然可以访问enum
值,但派生类的用户不会。
class Male : public Person {
public:
Male (std::string name) : Person(name, MALE) {}
//...
};
因此,Male
可以使用MALE
,但Male
的用户将看不到Male::MALE
,Male::FEMALE
和Male::BOTH
,是你最初的问题之一。至于你的问题,你并不想拒绝派生类访问,因为你希望派生类能够指定Gender
。你不应该真正允许Person
的任何直接用户。相反,Person
的用户选择一个正确的派生类,然后正确地建立Gender
。
class Female : public Person {
public:
Female (std::string name) : Person(name, FEMALE) {}
//...
};
class Transgender : public Person {
public:
Transgender (std::string name) : Person(name, BOTH) {}
//...
};
std::shared_ptr<Person> p = std::make_shared<Female>("Beth");
答案 1 :(得分:1)
OP中的评论建议重新考虑您的设计,可能这是最佳选择。
尽管如此,如果你想跟上你在答案中写的内容,一种可能性是从你的基类派生protected
class Person {
public:
enum { MALE, FEMALE, BOTH };
Person(std::string name, int gender)
: _name(name)
{
switch (gender) { /* processing here */ }
}
protected:
std::string _name;
};
class Male : protected Person
{ //^^^^^^^^^
public:
Male(std::string name)
: Person(name, 0) { }
void foo() { FEMALE; } // still ok, a public field derived protected'ly is accessible
};
int main()
{
Male male("Joe");
male.MALE; //error, cannot call the enum from outside the class
}
答案 2 :(得分:0)
问题似乎是一个有文化的问题,代码本身没有问题,但是在将代码视为反映常见概念的语言时。
从这个意义上讲,我会建议以下答案:
有一个工厂(或工厂方法),其中枚举仅在该工厂公开。换句话说,创建一个新工厂Human
并使用Human
枚举包含所有基类和派生类。然后基类仍然可以是Person
,但Person
没有任何枚举MALE
/ FEMALE
/等......只有Human
工厂才有,并且它不是子类的基类。这将导致代码可以像下面这样读取:
Person person("The Name", Human::MALE);
你也可以像这样使用Gender
工厂(而不是Human
)(为了更有文化并将相互依赖性分开):
Person person("The Name", Gender::MALE);
请注意,基类包含所有派生类必须共享的最小公分母。因此,由于派生类Male
Female
等不应该共享gender enum
,所以它不应该是基类的一部分,而是本身的一个类或构造,然后由Person
类及其衍生物。
答案 3 :(得分:-1)
使用受保护的构造函数简单地创建Person
类摘要:
class Person {
public:
enum Gender {
MALE,
FEMALE,
BOTH
};
protected:
// Protected constructor can only be called from subclasses.
Person(std::string name, Gender gender)
: _name(name)
{
switch (gender) { /* processing here */ }
}
protected:
std::string _name;
};
class Male : public Person {
public:
Male(std::string name)
: Person(name, MALE)
{
}
};
如果性别无论如何独立于Person类,只需将其移出类:
enum Gender {
GenderMale,
GenderFemale,
GenderBoth
};
class Person //...
class Male // ...
您还可以将Gender封装到自己的类中:
class Gender {
public:
enum Type { Male, Female, Both };
Gender(Type type);
Gender(const Gender ©);
Gender& operator=(Gender &assign);
public:
bool operator==(const Gender &other) const;
// etc.
public:
std::string toString() const;
};