C++ 防止继承基 class 的特定 public 成员
C++ prevent inherit specific public member of base class
如何防止 public 成员被派生的 class 继承?就像,如果我有这个:
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) { }
};
我想这样做的原因是,我希望能够实例化一个人 class 像这样的东西:
Person person("The Name", Person::MALE);
但是,因为 enum
是 public 这也可用:
Male::MALE
Male::FEMALE
Male::BOTH
这已经没有任何意义了。如何防止派生的 class 能够访问这些枚举值,但使其可用于基数 class?
的 public
OP 中的评论建议重新考虑您的设计,这可能是最好的选择。
不过,如果您想跟上您在答案中所写的内容,一种可能性是从您的基础 class
派生 protected
ly
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
}
如果您坚持将 enum
保留在基础 class 内,您可以将 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
公开派生的 class 仍然可以访问 enum
值,但派生 class 的用户将不能。
class Male : public Person {
public:
Male (std::string name) : Person(name, MALE) {}
//...
};
因此,Male
可以使用 MALE
,但 Male
的用户将看不到 Male::MALE
、Male::FEMALE
,也不会看到 Male::BOTH
,这是您的原始问题之一。至于您的问题,您并不是真的想拒绝派生 class 访问,因为您希望派生 class 能够指定 Gender
。而且你真的不应该允许 Person
的任何直接用户。相反,Person
的用户选择一个正确的派生 classes,然后它将正确地建立 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");
问题似乎是识字问题,代码本身没有问题,但将代码视为一种反映共同观念的语言。
从这个意义上说,我会建议以下答案:
有一个工厂(或工厂方法),其中枚举仅在该工厂中 public。换句话说,创建一个新工厂 Human
并使用 Human
枚举拥有所有基础和派生的 classes。然后基础 class 仍然可以是 Person
但 Person
没有任何枚举 MALE
/FEMALE
/etc.. 只有 Human
工厂确实如此,而且它不是 subclass 的基础 class。这将导致可以像这样按字面意义阅读的代码:
Person person("The Name", Human::MALE);
您也可以像这样使用 Gender
工厂(而不是 Human
)(更加识字并分离相互依赖性):
Person person("The Name", Gender::MALE);
请注意,基础 class 包括所有派生的 classes 必须共享的最小公分母 。因此,由于派生的 classes Male
Female
等不应该共享 gender enum
那么它不应该是基础 class 的一部分,而是 class 或自身构造,然后由 Person
classes 及其衍生物使用。
使用受保护的构造函数简单地创建 Person
class 抽象:
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)
{
}
};
如果性别无论如何独立于人 class,只需将其移出 class:
enum Gender {
GenderMale,
GenderFemale,
GenderBoth
};
class Person //...
class Male // ...
也可以把Gender封装成自己的class:
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;
};
如何防止 public 成员被派生的 class 继承?就像,如果我有这个:
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) { }
};
我想这样做的原因是,我希望能够实例化一个人 class 像这样的东西:
Person person("The Name", Person::MALE);
但是,因为 enum
是 public 这也可用:
Male::MALE
Male::FEMALE
Male::BOTH
这已经没有任何意义了。如何防止派生的 class 能够访问这些枚举值,但使其可用于基数 class?
的 publicOP 中的评论建议重新考虑您的设计,这可能是最好的选择。
不过,如果您想跟上您在答案中所写的内容,一种可能性是从您的基础 class
派生protected
ly
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
}
如果您坚持将 enum
保留在基础 class 内,您可以将 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
公开派生的 class 仍然可以访问 enum
值,但派生 class 的用户将不能。
class Male : public Person {
public:
Male (std::string name) : Person(name, MALE) {}
//...
};
因此,Male
可以使用 MALE
,但 Male
的用户将看不到 Male::MALE
、Male::FEMALE
,也不会看到 Male::BOTH
,这是您的原始问题之一。至于您的问题,您并不是真的想拒绝派生 class 访问,因为您希望派生 class 能够指定 Gender
。而且你真的不应该允许 Person
的任何直接用户。相反,Person
的用户选择一个正确的派生 classes,然后它将正确地建立 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");
问题似乎是识字问题,代码本身没有问题,但将代码视为一种反映共同观念的语言。
从这个意义上说,我会建议以下答案:
有一个工厂(或工厂方法),其中枚举仅在该工厂中 public。换句话说,创建一个新工厂 Human
并使用 Human
枚举拥有所有基础和派生的 classes。然后基础 class 仍然可以是 Person
但 Person
没有任何枚举 MALE
/FEMALE
/etc.. 只有 Human
工厂确实如此,而且它不是 subclass 的基础 class。这将导致可以像这样按字面意义阅读的代码:
Person person("The Name", Human::MALE);
您也可以像这样使用 Gender
工厂(而不是 Human
)(更加识字并分离相互依赖性):
Person person("The Name", Gender::MALE);
请注意,基础 class 包括所有派生的 classes 必须共享的最小公分母 。因此,由于派生的 classes Male
Female
等不应该共享 gender enum
那么它不应该是基础 class 的一部分,而是 class 或自身构造,然后由 Person
classes 及其衍生物使用。
使用受保护的构造函数简单地创建 Person
class 抽象:
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)
{
}
};
如果性别无论如何独立于人 class,只需将其移出 class:
enum Gender {
GenderMale,
GenderFemale,
GenderBoth
};
class Person //...
class Male // ...
也可以把Gender封装成自己的class:
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;
};