C++ prevent inherit specific public member of base class - c++

How can I prevent a public member to be inherited by it's derived class? Like, if I have this:
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) { }
};
The reason I want to do this is, I want to be able to instantiate a person class with something like:
Person person("The Name", Person::MALE);
But, because the enum is public this is also available:
Male::MALE
Male::FEMALE
Male::BOTH
which doesn't make any sense anymore. How can I prevent the derived class to be able to access those enum values, but make it available for public from the base class?

If you insist on keeping the enum within the base class, you can place the enum in a protected section.
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 () {}
//...
};
A class that derives from Person publicly will still have access to the enum values, but users of the derived class will not.
class Male : public Person {
public:
Male (std::string name) : Person(name, MALE) {}
//...
};
Thus, a Male can use MALE, but users of Male will not see Male::MALE, Male::FEMALE, nor Male::BOTH, which was one of your original issues. As to your questions, you don't really want to deny the derived class access, since you want the derived class to be able to specify the Gender. And you should not really allow any direct users of Person. Instead, a user of Person picks one of the correct derived classes, which will then establish Gender properly.
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");

The comments in the OP suggest a rethinking of your design, and probably that is the best alternative.
Still, if you want to keep up with what you wrote in the answer, one possibility is to derive protectedly from your base 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 : 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
}

the problem seems to be a literate one, there is no problem with the code per se, but in viewing the code as a language reflecting common notions.
In this sense i would suggest the following answer:
have a factory (or factory method) where the enum is public only in that factory. In other words create a new factory Human and have all base and derived classes using Human enums. Then the base class can still be Person but Person does not have any enum MALE/FEMALE/etc.. only the Human factory does, and it is not a base class that is subclassed. This would result in code which can be read literaly like this:
Person person("The Name", Human::MALE);
You can also use Gender factory (instead of Human) like this (to be even more literate and separate the inter-dependencies):
Person person("The Name", Gender::MALE);
Note that a base class includes the lowest common denominator that all derived classes must share. So since the derived classes Male Female etc are not supposed to share the gender enum then it should not be part of the base class, but a class or construct in itself which is then used by Person classes and its derivatives.

Simple make the Person class abstract using a protected constructor:
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)
{
}
};
If the gender is anyway independent from the Person class, just move it out of the class:
enum Gender {
GenderMale,
GenderFemale,
GenderBoth
};
class Person //...
class Male // ...
You can also encapsulate the Gender into a own class:
class Gender {
public:
enum Type { Male, Female, Both };
Gender(Type type);
Gender(const Gender &copy);
Gender& operator=(Gender &assign);
public:
bool operator==(const Gender &other) const;
// etc.
public:
std::string toString() const;
};

Related

Setting value using base class functions from derived class

I'm new to c++. I'm trying to complete a c++ assignment involving Inheritance where the Car class must contain these methods setGarageSpaces function to set garage space to 2, and setNumWheels function to set wheels to 4.
I'm creating a no parameter constructor and inheriting from the base class Vehicle then using the set functions but I'm getting an error.
#include <iostream>
using namespace std;
class Vehicle
{
public:
Vehicle();
void setGarageSpaces(size_t spaces)
{
garage_spaces_ = spaces;
}
void setNumWheels(size_t wheels)
{
num_wheels_ = wheels;
}
Vehicle(std::string name, std::string manufacturer, double top_speed, double weight, double mpg, double curr_gas_amt);
protected:
size_t garage_spaces_; // number of garage slots this vehicle takes up
size_t num_wheels_;
};
class Car : public Vehicle { //Car derived class inherits from base class Vehicle
public:
Car(){ //no para constructor
setGarageSpaces(2);
setNumWheels(4);
}
Car(std::string name, std::string manufacturer, double top_speed, double weight, double mpg);
};
int main() {
Car c;
}
public:
Vehicle();
Default Constructor for Vehicle is not implemented, you may want to do :
public:
Vehicle() {}
When you expect proper construction, you can remove the default constructor from class, forcing user to impl. the proper constructor call.

How to get parent class name, from child

i have something similar configData:
class all {
public:
class animals {
public:
class animalPatern {
public:
int hp = 80;
std::string name = "no name";
};
class cow : public animalPatern {
public:
std::string name = "big cow";
};
class bird : public animalPatern {
public:
std::string name = "small bird";
};
};
};
how can i get parent class name animalPatern by children class bird, for template i can use std::is_base_of, cannot find some information how to do for class...
as well as the ability to get all child classes name, like animals have: animalPatern,cow ,bird

Edit variables inherited from parent class

I have this code for a basic entity system I'm testing
Enity.h
class Enemy
{
public:
void attack(Player player);
virtual void die();
protected: //Info variables
int attackDamage;
std::string name;
bool alive;
}
class ChildEnemy1 : public Enemy
{
name = "Enemy1" //Invalid
};
class ChildEnemy2 : public Enemy
{
name = "Enemy2" // Invalid
};
How would you change the Info variables (attackDamage, name, alive) without inheriting a public setter function
(retain encapsulation).
EDIT: This is not a duplicate question as I have not found an adequate answer to this problem on SO
Initialize the members in the constructor.
class ChildEnemy1 : public Enemy
{
ChildEnemy1() : name("Enemy1") {}
};

c++: What is a good refactor for a duplicate member field in the subclass of a multiply-inherited class?

Title edits that reflect a better summary of the question are welcome.
I'd like to refactor these three classes somehow to remove the duplicate field represented in class C (see hierarchy). I thought about pulling the field up into a parent class, but the issue is that A and B are not similar enough to be considered "is-a", C is considered both, and it is literally only one member field so creating a class just to hold ONE THING seems a bit overkill.
Hierarchy:
(abstract data type)
class A : public O {
public:
//...
std::string GetName();
std::string GetName() const;
void SetName(std::string name);
//...
protected:
//...
std::string _name;
//...
};
//Methods and fields shown here represent the exact same representative data as in A but the classes are so dissimilar as to not be considered "is-a" relationship.
(abstract data type)
class B {
public:
//...
std::string GetName();
std::string GetName() const;
void SetName(std::string name);
//...
protected:
//...
std::string _name;
//...
};
(concrete)
class C : public A, public B {
public:
//...
C(/*..Other parameters..*/, std::string name, /*....*/)
: A(name, /*...*/), B(name, /*...*/) {
/*...*/
}
//...
private:
//...
};
You can either leave it as-is, as said previously or you can consider using composition over inheritance for class C like:
class C : public A
{
public:
// ...
// The GetName and SetName methods are inherited from A.
private:
B* b;
};
or
class C
{
public:
// ...
std::string GetName();
std::string GetName() const;
void SetName(std::string name);
private:
A* a;
B* b;
};
Looking at this question and answers: Get rid of ugly if statements clearly shows that, as #Andre mentioned, your current code is perfectly acceptable and trying to "fix" it may cause same pain and mind blow.
Leave it AS-IS, it's good.
Since C is passing in the same name parameter to both A and B, you might be able to get what you want with virtual inheritance. V below is defined to be a common base class for A, B, and C, but with virtual inheritance, they all share the same instance.
class V {
public:
std::string GetName();
std::string GetName() const;
void SetName(std::string name);
protected:
std::string _name;
V () {}
V (std::string n) : _name(n) {}
~V () {}
};
class A : virtual public V, public O {
//...
};
class B : virtual public V {
//...
};
class C : virtual public V, public A, public B {
public:
C (/*...otherargs,*/std::string name/*,moreargs...*/)
: V(name), A(/*...*/), B(/*...*/) {
//...
}
//...
};

C++ multiple inheritance

Please don't question the really odd hierarchy of workers in this code here, I have no idea why anyone would want something like this, but I decided to give myself an exercise in Multiple Inheritance, just to be sure I fully understood it. So here's the result.
using namespace std;
class Employee
{
protected:
string name;
public:
string getname()
{
return name;
}
void setname(string name2)
{
name = name2;
}
Employee(string name2)
{
name = name2;
}
Employee(){}
};
class Manager : public Employee
{
public:
string getname()
{
return ("Manager" + name);
}
Manager(string name2) : Employee(name2){}
Manager() : Employee(){}
};
class Supervisor : public Manager,public Employee
{
public:
Supervisor(string name2) : Manager(name2) , Employee(name2){}
Supervisor() : Manager() , Employee(){}
string getname()
{
return ("Supervisor" + Employee::getname());
}
};
Hopefully you're understanding what I'm trying to do here. I'm getting something about an "ambiguous conversion between derived class 'Supervisor' and base class 'Employee.'" So what do I do?
Actually, the way you have defined Supervisor class, its object will have two subjects of type Employee, each coming from it base classes. That is causing problem.
The solution is to use virtual inheritance (assuming you need multiple inheritance) as:
class Manager : public virtual Employee
Hope you note the virtual keyword here. :-)
Everybody has already covered virtual inheritance, but I'd suggest reading the C++ FAQ as well.
http://www.parashift.com/c++-faq-lite/multiple-inheritance.html
You need a virtual inheritance in this case:
#include <iostream>
#include <string>
using namespace std;
class Employee
{
protected:
string name;
public:
string getname()
{
return name;
}
void setname(string name2)
{
name = name2;
}
Employee(string name2)
{
name = name2;
}
Employee(){}
};
class Manager : public virtual Employee
{
public:
string getname()
{
return ("Manager" + name);
}
Manager(string name2) : Employee(name2){}
Manager() : Employee(){}
};
class Supervisor : public Manager,public virtual Employee
{
public:
Supervisor(string name2) : Manager(name2) , Employee(name2){}
Supervisor() : Manager() , Employee(){}
string getname()
{
return ("Supervisor" + Employee::getname());
}
};
This problem is also known as Diamond inheritance problem:
http://en.wikipedia.org/wiki/Diamond_problem
Supervisor contains two objects of type Employee, the direct one and the one over Manager. It is ambiguous to call Employee methods on a Supervisor in consequence (which Employee should be called?). You might want to employ virtual multiple inheritance instead.