Access child members within parent class when children are inside a vector of type parent
You just experimented slicing.
A Child
is a Parent
plus a few more things.
When you try to put a Child
in the vector of Parent
, only the Parent
part of each of these Child
ren is put in the vector (because the vector does not contain Child
ren but Parent
s); hence the name slicing.
In order to obtain the dynamic polymorphism you are looking for, you need a vector of pointers to Parent
; this way, each pointed-to element can be whether a Parent
or a Child
and behave accordingly.
This is often done with a dynamic allocation of each element in the vector, but this is not mandatory. For example, you could store all the Parent
s in a vector, all the Child
ren 1 in another, and so on, and finally use a vector of pointers to designate some of them in any order.
If you decide to allocate each Parent
/Child
individually, you should consider smart-pointers like std::unique_ptr<T>
rather than raw pointers and new
/delete
.
You will find below your example slightly modified in order to obtain dynamic polymorphism.
It relies on dynamic allocation of each element thanks to std::unique_ptr<T>
/std::make_unique()
.
Note that, because of dynamic polymorphism, you need a virtual
destructor (even if it does nothing special).
Since this hierarchy of types is intended for dynamic polymorphism, it is encouraged to prevent slicing (that you have just experienced) by forbidding the use of copy/move operations.
Thus, you have to provide one or several constructors that fulfil your needs (but this is quite common).
My last advice is « avoid dynamic polymorphism; prefer template
» but it is another topic ;^)
/**
g++ -std=c++17 -o prog_cpp prog_cpp.cpp \
-pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
-g -O0 -UNDEBUG -fsanitize=address,undefined
**/
#include <iostream>
#include <string>
#include <vector>
#include <memory> // std::unique_ptr<T>, std::make_unique()
class Parent
{
public:
virtual ~Parent() =default; // ensure correct destruction
// forbid copy and move in order to prevent slicing
Parent(const Parent &) =delete;
Parent &operator=(const Parent &) =delete;
Parent(Parent &&) =delete;
Parent &operator=(Parent &&) =delete;
Parent() =default; // provide a suitable constructor
virtual
const std::string &
getType() const
{
return type;
}
private:
// inline static // is probably better
const std::string type{"parent"};
};
class Child1: public Parent
{
public:
const std::string &
getType() const override
{
return type;
}
private:
// inline static // is probably better
const std::string type{"type1"};
};
class Child2 : public Parent
{
public:
const std::string &
getType() const override
{
return type;
}
private:
// inline static // is probably better
const std::string type{"type2"};
};
int
main()
{
const auto p=Parent{};
std::cout << "p: " << p.getType() << '\n';
const auto c1=Child1{};
std::cout << "c1: " << c1.getType() << '\n';
const auto c2=Child2{};
std::cout << "c2: " << c2.getType() << '\n';
auto people=std::vector<std::unique_ptr<Parent>>{};
for(auto i=0; i<2; ++i)
{
people.emplace_back(std::make_unique<Parent>());
people.emplace_back(std::make_unique<Child1>());
people.emplace_back(std::make_unique<Child2>());
}
for(const auto &e: people)
{
std::cout << e->getType() << '\n';
}
return 0;
}
Access child members within parent class, C++
The only clean way is to use the virtual function approach.
If the Parent
class has at least one virtual function (not necessarily DoSomething
), there's also a yucky way to do it:
void DoSomething() {
if (Child1* child = dynamic_cast<Child1*>(this)) {
child->childMember = 0;
} else if (Child2* child = dynamic_cast<Child2*>(this)) {
child->childMember = 0;
} // and so on, and so forth
}
(If Parent
has no virtual functions, then the dynamic_cast
won't work. Though, any class designed to be inherited from should have at least one virtual function, even if it's just the destructor.)
How can I access a child class member stored in a parent class?
root
is a Node pointer. root->right
is another Node pointer. root->right->down
is--you guessed it--a Node pointer.
When you do [...]->value
, you're dereferencing that Node pointer, which gives you a Node, and then trying to get the value
member on it. But Node has no value
member!
You could attempt to cast your Node pointer into an ENode pointer, using dynamic cast. Which would look like:
Node *n = root->right->down;
if(ENode *en = dynamic_cast<ENode*>(n)) {
std::cout << en->value << std::endl;
} else {
std::cout << "That's not an ENode!" << std::endl;
}
But to do this, you'll need to make Node polymorphic (which you can see detailed here).
Also note that in production code, you should be checking to make sure root
, root->right
and root->right->down
are all non-null before going ahead and dereferencing them.
C++ : Access of a child member from a parent class
Not really giving you access to child member, but this is a more OOP approach.
If the only thing you were trying to do is to print the different types of Person
classes, then a more proper way of doing it is to define a virtual
print
function in Person
class, then override print
function in each child classes, and call person->print()
in your Booking
class.
In your Person
class:
class CPerson
{
public:
virtual void Print()
{
std::cout << Name << "\n";
}
protected:
std::string Name;
}
In your Student
class:
class CStudent
{
public:
void Print()
{
CPerson::Print(); // this will execute the Print() you defined in CPerson
std::cout << MatriculationNr << "\n";
// Or you can also just cout all information from here:
// std::cout << Name << ", " << MatriculationNr << "\n";
}
private:
int MatriculationNr;
}
Then in your Booking
class, you just call print()
from all Person
:
void CBookings::Print()
{
for (int i = 0 ; i < Persons.size() ; i++)
{
Persons[i]->Print();
}
}
By doing this, you also don't need to declare Booking
as a friend
in Person
class.
Edit:
In case you were wondering why you want to do it this way:
The fact you used a vector<Person*>
implied that there might be other types of Person
included in the vector, such as Staff
. If not, then you should have just used vector<Student*>
instead.
In the case you might also have Staff
in it, then doing something like:
std::cout << Persons[i]->MatriculationNr
wouldn't make any sense because of course Staff
would not have such member in it. Instead, Staff
might have a Salary
, or whatever in it.
If you keep using the friend
class to access private
members, you would also need to check each Person
's type, if they are a Student
or a Staff
, then call different cout
function based on that.
This becomes tedious if you have many different children types, and your Booking::Print()
just becomes a huge if
- else if
- else if
block. And you have to update Booking
every time you either change the members of your Person
classes, or add another child class to Person
.
By having overridden Print()
function in your children classes, you don't need to do anything to Booking::Print()
, they would all use the same person->Print()
from your Booking
class.
the child class always have access to the public members of its parent, why and how it is possible?
Using public inheritance, your derived class will have access to protected and public fields and methods declared in the base class. However, your base class doesn't know about your derived class at all. Inheritance only works one way. You basically extend the functionality of a class.
You can think of it as putting a smaller box into a larger one. Each box knows what's inside it, but it doesn't know what's outside of it. The base class is the smaller box, the derived one is the larger box.
How can I access child class version of functions in the parent class from the child class if the objects are in a vector?
If you have a vector of ParentCLass
objects, that will hold ParentClass
objects. When you add a ChildClass
, C++ will need to apply a conversion - push_back
takes ParentCLass const&
. The conversion found is the standard child to parent conversion; so the parent part is copied.
This is called "slicing". You can create a std::vector<std::unique_ptr<ParentClass>>
instead. This won't slice the object, since the vector only holds (smart) pointers to the objects.
Access child class' functions within parent class
You might want to take a look at the visitor pattern.
In essence, the visitor allows one to add new virtual functions to a family of classes without modifying the classes themselves; instead, one creates a visitor class that implements all of the appropriate specializations of the virtual function. The visitor takes the instance reference as input, and implements the goal through double dispatch.
The double dispatch means you are actually calling a virtual function twice: first on the subject which in turn polymorphically calls the visitor.
In your case there is just one method, namely building houses, but you might want to add others later (like drawing them on a screen for example). Given your current example you should add this method to Tile and StreetTile:
virtual void accept(Visitor& v) { v.visit(*this); }
This is the Visitor base class implementation:
class Visitor {
public:
virtual void accept(Tile& t) = 0;
virtual void accept(StreetTile& t) = 0;
};
After that you can implement a Builder class:
class Builder: public Visitor {
private:
int numberOfHouses;
public:
Builder(int n): numberOfHouses(n) {}
virtual void accept(Tile& t) {}
virtual void accept(StreetTile& t) {
t.buildHouses(numberOfHouses);
}
};
After that all you have to do is construct such a builder, and call it on every tile in your vector of tiles:
Builder b(10);
for (Tile tile : tiles) {
tile.accept(b);
}
Is it possible to access child class members that are not in parent class from a parent class type reference variable pointing to child class object?
You are right, you cannot write:
employee.AnnualSalary = 1234;
But this is not your case.
You are just using an object initializer to initialize a FullTimeEmployee
object(You have access to all public fields/properties).
Basically you are doing the following:
FullTimeEmployee employeeTemp = new FullTimeEmployee();
employeeTemp .AnnualSalary =2000;
Employee employee =employeeTemp;
Update
I thought one can not typecast parent class object to child class
object since a child can do everything that parent can but vice versa
is not true.
Once again you are right.
And once again this is not your case...
The return type of the method might be Employee but the actual object you return might be something else (a derived class).
In this case you can safely cast the object to your derived type.
Check the following example
namespace CastExample
{
class Program
{
static void Main(string[] args)
{
Employee emp = GetEmployee();
FullTimeEmployee full = (FullTimeEmployee)emp;
System.Console.WriteLine(full.AnnualSalary);
PartTimeEmployee part = (PartTimeEmployee)emp;//InvalidCastException
System.Console.ReadLine();
}
static Employee GetEmployee()
{
return new FullTimeEmployee() { Name = "George", AnnualSalary = 1234 };
}
}
public class Employee
{
public string Name;
}
public class FullTimeEmployee : Employee
{
public int AnnualSalary { get; set; }
}
public class PartTimeEmployee : Employee
{
public int HourlyPay { get; set; }
public int HoursWorked { get; set; }
}
}
And he can access private properties too??
Yes,you can access private fields using reflection
Find a private field with Reflection?
How to get the value of private field in C#?
c# use reflection to get a private member variable from a derived class
Check this :
Why can reflection access protected/private member of class in C#?
@Marc Gravell's answer explain why you can do this but pay special attention to @Tamas Czinege's answer (I quote it here again)
Member accessibility is not a security feature. It is there to protect
the programmer against himself or herself. It helps implementing
encapsulation but it is by no means a security feature.
Related Topics
Read Qprocess Output to String
Most Efficient Replacement for Isbadreadptr
Random Numbers for Multiple Threads
How to Know When a New Usb Storage Device Is Connected in Qt
What Is a Cross-Platform Way to Get the Current Directory
Thread Safety of Matlab Engine API
How to Check If a File Is Still Being Written
Floating Point to Binary Value(C++)
Tool to Generate Xml File from Xsd (For Testing)
Best C++ Matrix Library for Sparse Unitary Matrices
Why Does Gcc Not Seem to Have the Filesystem Standard Library
Absence of Typeof Operator in C++03
What Is the Fastest Way to Compute Large Power of 2 Modulo a Number