I understand that a private protection level is meant to stop any child accessing private parent variables.
But isn't there a way to do it with accessors and mutators(get and set)? I have to have some kind of way to change a private string because that is the homework.
I have a public abstract pet class with a private string for a name. I want to create a dog and use that string name. I can't figure it out though. Since it is homework, I understand I cannot be given code or anything, but could someone point out the method to do this so I can google it? All my searches just imply that it is impossible.
Here's my code if it will help.
edit I can't just make it protected.
public abstract class Pet
{
private string name;
private string species;
public abstract void speak();
public abstract void play();
public abstract void info();
}
Part of the child dog class...
class Dog : Pet
{
public Dog(string xname, string xspecies)
{
this.name = xname; // this is where I'm having trouble.
}
Let's make sure that you have a clear and accurate understanding; many beginners are taught subtle falsehoods.
I understand that a private protection level is meant to stop any child accessing private parent variables.
That's a correct summary of the intention of the feature. Basically you are saying that access control modifiers are for controlling access, which should not be a surprise.
However there are two subtleties that I want to point out here.
The first is that access modifiers control access to the names of things, not to the things. When you have a member named foo
, the name foo
may only be used to refer to that member from within the accessibility domain of that member. The "accessibility domain" is a region of program text; the accessibility domain of a private member is the text of the type which declares the member.
If you have come up with some other way to refer to a member, that mechanism is not controlled by the accessibility modifier. The only thing an accessibility modifier controls is where the name may be used in the text of the program.
Make sure that is clear in your head.
Second, you note that a private
member is not accessible to a "child", by which I assume you mean a derived class. There is a situation in which a derived class can access private member by name. Given what I've said so far, you should be able to deduce what it is. Give it some thought and then read on.
I said that a private member is accessible by name only inside the text of the declaring type, so if a private member is accessible by name by a derived class, the derived class must be inside the text of the declaring type:
class Base
{
private static int x;
class Derived : Base
{
static void M() { Console.WriteLine(Base.x); }
}
}
This is legal because x
is used by name inside its accessibility domain.
So, how do you do your homework problem? There are only two ways:
(1) Put Dog
inside of Pet
; any Dog
then has access to all the private members of Pet
. This is a "for advanced players only" feature of C# and almost certainly not what your instructor is looking for. But it is a really powerful technique and I use it frequently, so keep it in mind for your later career; in particular, when you learn about the "factory pattern" you can pull out of your back pocket the knowledge that putting the derived classes inside the base class is a good trick for making the factory pattern work well.
(2) Make some accessor mechanism for the private member, and make that accessor mechanism's name protected, internal, or public.
Typically you'd use a property. You make an property with a read-only accessor in C# like this:
class Base
{
private int x;
public int X { get { return x; } }
}
Or, in more modern versions of C# you can use this short form:
public int X => x;
And now code outside of Base
cannot use x
by name, because that is outside of the accessibility domain of Base.x
. But X
has an unrestricted accessibility domain, so it can be used anywhere you like.
That's a read-only accessor. To make a write accessor you add a setter:
public int X
{
get { return x; }
set { x = value; }
}
Notice that setters have a magic value
name that is the value that is to be assigned to the property.
There are other ways to make accessors but this is by far the most common.
While we are looking at your code, a couple other things:
(1)
public abstract void speak();
public abstract void play();
public abstract void info();
Public methods should be PascalCasedLikeThis
, not lowercase
, in C#. It's just an arbitrary convention that makes it easier to read your code.
(2)
Why is info
void returning? Surely it should be returning some info.
(3)
class Dog : Pet
Is your intention to further subclass Dog
? Probably not, because it is not abstract
. Consider marking classes not intended to be subclassed as sealed
, so that you do not have to worry about designing the class for safe inheritance.