I'm trying to use multiple inheritance. Person is my base class. Student and Angestellter inherit the protected attributes. WissenschaftlicheHilfskraft should also inherit these attributes (from Person, Student, Angestellter), but I can't call the method get_name() in my last derived class. Why?
#include <iostream>
using namespace std;
class Person {
protected:
string name;
public: //.......
string get_name() { name = "bob"; return name; }
};
class Student: public Person {
private: //......
public: //......
};
class Angestellte: public Person {
private: //......
public: //......
};
class WissenschaftlicheHilfskraft : public Student, public Angestellte
{
private: //......
public: //......
};
int main()
{
Person p;
cout << p.get_name() << endl; //WORKS
Student s;
cout << s.get_name() << endl; //WORKS
Angestellte a;
cout << a.get_name() << endl; //WORKS
WissenschaftlicheHilfskraft wh;
cout << wh.get_name() << endl; //DOESN'T WORK
return 0;
}
I want it to look like this:
Also, other than Paul R's answer your inheritance is wrong. You need to use virtual inheritance like as shown here.
class Student: public Person { becomes class Student: public virtual Person { and so on. This ensures that only one object of base is created for the final object.
This is the classic "diamond" problem with multiple inheritance. You can work around this by removing the ambiguity, e.g. change:
cout << wh.get_name() << endl; //DOESN'T WORK
to:
cout << wh.Student::get_name() << endl; //WORKS
However, see #Shiv's answer for a better solution which properly resolves the underlying problem.
Related
hello i am trying to create a class that uses inheritance from class Student to class Graduate Student but program says it is inaccessible.
class Student
{
Student(char* n, int id)
{
name = new char[strlen(n) + 1];
strcpy_s(name,strlen(n)+1, n);
studentId = id;
}
~Student()
{
if (name != NULL)
delete[]name;
}
void printStudent()
{
cout << "Student ID: " << studentId << "\nStudent Name: " << name << endl;
}
protected:
int studentId;
char* name;
};
class GraduateStudent :public Student
{
public:
GraduateStudent(char* n, char* a, int id) : Student(n, id)
{
area = new char[strlen(a) + 1];
strcpy_s(area, strlen(a) + 1, a);
}
~GraduateStudent()
{
if (area != NULL)
delete[]area;
}
void printGrad()
{
printStudent();
cout << "Research area: " << area << endl;
}
private:
char* area;
};
the program is supposed to print out an initiallised GraduateStudent class variable be calling printStudent();
Default access for a class is private, which makes OP's functions private.
So, your constructor is private.
You should read this.
Also, does this answer your question?
thx for edits #sweenish
When you are creating your classes, you may define access modifiers or access specifiers.(https://en.cppreference.com/w/cpp/language/access) (These are those words such as public, private or protected in your class). You may find [doc here]
class myClass{
public:
// public members go here
protected:
// protected members go here
private:
// private members go here
};
To make it simple, they allow you to tell whether a member should be accessible from everywhere, from derived classes only or not at all from outside the class where it is defined. When you do not put anything, in a C++ class, it means that it is private by default.
Thus your printStudent() method is private and cannot be accessed from your GraduateStudent class.
A good starting point for more details and more understanding of the notion is to read some tutorials
To solve your compilation problem, you should make your Student constructor, destructor and printStudent as public to allow the derived class to access them and compile.
class Student
{
public:
Student(char* n, int id)
{
...
}
~Student()
{
...
}
void printStudent()
{
...
}
....
};
You declared int studentId; and char* name; as protected, so in GraduateStudent you can access them, so you can easily do:
void printGrad() {
cout << "Student ID: " << studentId << "\nStudent Name: " << name << endl;
cout << "Research area: " << area << endl;
}
or, alternatively, declare printStudent(); in the public part of Student. In fact, if you declare something without any kind of specification, in a class, it is private by default, while in a struct, it is public.
Is there a way to access superclass methods from a subclass?
I made Apple class as a subclass of Fruit class, but I can not access to setName function in Fruit class from an object of Apple class.
Could you give me any advice?
#include <iostream>
#include <string>
using namespace std;
class Fruit {
public:
Fruit(string str)
{
cout << "Fruit class" << endl;
name = str;
cout << name << endl;
}
void setName(string str) {
name = str;
}
private:
string name;
};
class Apple:Fruit {
public:
Apple() :Fruit("apple"){
cout << "Apple class" << endl;
}
void setName(string str) {
name = str;
}
};
int main()
{
Apple apple;
apple.setName("Orange"); //I can not access to setName function from apple
return 0;
}
Use public inheritance like this:
class Apple : public Fruit
The default visibility for class is private if it's not specified. That is why you're not able to access the public members of the base class because they're now private due to their private visibility.
Contrary to a class, the default visibility for a struct is public i.e.:
struct Base {};
struct Derived : Base {}; // public inheritance
In your code, the overridden setName() method in the derived class is redundant as it cannot manipulate the private data member name directly. You'll have to use the base class method to set the name in your overridden method. As of now, you're not doing anything else in that method so you don't need it.
Here's your working code (live):
#include <iostream>
#include <string>
using namespace std;
class Fruit {
public:
Fruit(string str)
{
cout << "Fruit class" << endl;
name = str;
cout << name << endl;
}
void setName(string str) {
name = str;
}
private:
string name;
};
class Apple : public Fruit { // public inheritance
public:
Apple() :Fruit("apple"){
cout << "Apple class" << endl;
}
// void setName(string str) { // Redundant!
// name = str; // `name` is not accessible here!
// }
};
int main()
{
Apple apple;
apple.setName("Orange"); // Accessible here
return 0;
}
For more relevant information, refer to this:
Difference between private, public, and protected inheritance
Your Apple class is using private inheritance (the default when the type of inheritance is not specified), so all of Fruit's public methods are private in Apple and thus are not accessible for main() to call. You need to use public inheritance instead to fix that.
Also, there is no need to re-implement setName() in Apple. The inherited setName() from Fruit will suffice, once it is inherited as a public method in Apple.
class Apple : public Fruit {
public:
Apple() : Fruit("apple"){
cout << "Apple class" << endl;
}
};
Use public inheritance
class Apple:public Fruit
in class Default is Private
class Apple:Fruit
is same as
class Apple:private Fruit
You made private here, So you can not access member of Fruit by object of Apple even if it is public.
class Apple:public Fruit
{
public:
Apple() :Fruit("apple")
{
cout << "Apple class" << endl;
}
};
Or if you want it is to private use like this
class Apple:Fruit
{
public:
Apple() :Fruit("apple")
{
cout << "Apple class" << endl;
}
void setName(string str)
{
Fruit::setName(str);
}
};
First, change class Apple to
class Apple: public Fruit
then, use this method
apple.Fruit::setname()
I don't know how access to private variable Multiple Inheritance.
In this code I create person class
class person {
char name[20]; char lname[20];
public:
person() {}
person(char*n, char*ln);
virtual void print(ostream&o);
};
person::person(char*n, char*ln)
{
strcpy_s(name, 20, n);
strcpy_s(lname, 20, ln);
}
void person::print(ostream&o)
{
o << "name: " << name << " " << "last name: " << lname << endl;
}
ostream& operator<<(ostream&o, person&p)
{
p.print(o);
return o;
}
by Inheritance I create student and teacher class
class student : public virtual person
{friend class ststudent;
long str;
public:
student(char*n, char*ln, long s);
void print(ostream&o);
};
student::student(char*n, char*ln, long s) :person(n, ln), str(s) {}
void student::print(ostream&o)
{
person::print(o);
o << "st_num : " << str << endl;
}
class teacher : public virtual person
{
long salary;
public:
teacher(char*n, char*ln, long s);
virtual void print(ostream&o);
};
teacher::teacher(char*n, char*ln, long sal) :person(n, ln), salary(sal) {}
void teacher::print(ostream&o)
{
person::print(o);
o << "salary : " << salary << endl;
}
and in last class I use from Multiple Inheritance to create teacher assistant class but I don't know how to print the str and salary
class stteacher :public teacher, public student
{
public:
stteacher(char*n, char*ln, long st, long sa)
:student(0, 0, st), teacher(0, 0, sa), person(n, ln) {}
virtual void print(ostream&o);
};
void stteacher::print(ostream& o)
{
person::print(o);
o << str << salary;
}
I don't know how to do it. I can create two variables in stteacher class or change str and salary from private to public variable but I think I should do this with Multiple Inheritance.
Help me please.
Private data in a class cannot be accessed by any non-member, non-friend code. Period. Whether you use inheritance (or not) is irrelevant.
Thus, the only way for a different class to access that data is to:
Provide accessor function(s) so that callers can fetch the data. (If public, anyone can call it, but if it's a protected function then only derived classes gain access to it.)
Alternately, make the class(es) that need access a friend of the class. Friendship is something c++ programmers generally discourage, however, so only do so as a true last resort.
Change the access to the data to be public. (Very discouraged, as this defeats encapsulation entirely.)
A pattern for accessing private variables is to make a public function that returns that variable:
class teacher : public virtual person
{
long salary;
public:
teacher(char*n, char*ln, long s);
virtual void print(ostream&o);
long get_salary(void){return salary;}
};
Then the implentation for stteacher::print would be:
void stteacher::print(ostream& o)
{
person::print(o);
o << get_salary();
}
or something like this.
Classes by default are private, which means that anything before specifying access modifiers is private.
Private methods / local variables can only be accessed by the class that defined them and it's friend classes. In your case, to define a friend class you should first tell to student and teacher what stteacher is.
C++ reads your code from top to bottom, so if you want to use a variable/class/macro/whatever, you should declare it above it's use.
In code, this would look something like:
extern class stteacher; //You tell C++ that 'stteacher' is a class
class person {};
class student : public virtual person {
long str;
friend class stteacher; //You make stteacher a friend of student
public:
student(long str) : str(str) {}
};
class teacher : public virtual person {
long salary;
friend class stteacher; //You make stteacher a friend of teacher
public:
teacher(long salary) : salary(salary) {}
};
class stteacher : public student, public teacher {
public:
stteacher(long str, long salary) : student(str), teacher(salary) {}
void print() {
std::cout << "Salary: " << salary << "\nStr: " << str << std::endl;
}
}
int main() {
long str = 10, salary = 100;
stteacher(str, salary).print();
return 0;
}
Salary: 100
Str: 10
Eventhough this works, I suggest it would be best to use a more apropiate access modifier, such as protected.
protected stuff can be accessed by the class which defines it, it's friend classes AND classes which inherits it.
Using protected access modifiers, the above code would look like:
extern class stteacher; //You tell C++ that 'stteacher' is a class
class person {};
class student : public virtual person {
protected: //Can be accessed by it's childs
long str;
public:
student(long str) : str(str) {}
};
class teacher : public virtual person {
protected: //Can be accessed by it's childs
long salary;
public:
teacher(long salary) : salary(salary) {}
};
class stteacher : public student, public teacher {
public:
stteacher(long str, long salary) : student(str), teacher(salary) {}
void print() {
std::cout << "Salary: " << salary << "\nStr: " << str << std::endl;
}
}
int main() {
long str = 10, salary = 100;
stteacher(str, salary).print();
return 0;
}
Salary: 100
Str: 10
It's said that with polymorphism, we can access a derived class member field with it's base class object like this:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Tool{
public:
Tool(){}
Tool(string name){
this->name = name;
}
virtual string getInfo(){
return name;
}
//protected:
string name;
};
class Computer: public Tool{
public:
Computer(string name, int price){
this->name = name;
this->price = price;
}
virtual string getInfo(){
return name + ": " + to_string(static_cast<long long>(price));
}
//protected:
int price;
};
class Person{
public:
Person(){}
Person(string name){
this->name = name;
}
virtual string getInfo(){
return name;
}
virtual void addTools(Computer cmp){
tools.push_back(cmp);
}
//protected:
vector<Tool> tools;
string name;
};
class Programmer: public Person{
public:
Programmer(string name, string job){
this->name = name;
this->job = job;
}
string getInfo(){
return name + ": " + job;
}
//protected:
string job;
};
int main(){
Person prs("Person");
Programmer prg("Daphloon", "programmer");
Person* prs1 = &prs;
Person* prs2 = &prg;
cout << prs1->getInfo() << endl; // result: Person
cout << prs2->getInfo() << endl; // result: Daphoon: programmer
Tool tl("Hammer");
Computer cmp("PC", 100);
Tool* tl1 = &tl;
Tool* tl2 = &cmp;
cout << tl1->getInfo() << endl; // result: Hammer
cout << tl2->getInfo() << endl; // result: PC: 100
prs2->addTools(cmp);
cout << prs2->tools[0].getInfo() << endl; // result: PC
// I expect the result will be: PC: 100
return 0;
}
The result wasn't what I expected. What I need is every derived class from Person have a vector tools that contains object that inherit from Tool class. If it described with word, it will be, "This Person, a Programmer, has some tools. His first Tool is a Computer. If you want to know what's it's price, use getInfo()."
Why vector take the base class instead of the derived class?
Is there any data loss from cmp object when i put it inside tools vector?
Is this happen because tools vector member take Tool as it's type?
Runtime polymorphism in C++, achieved via virtual functions, works on covariant types. The only covariant types are pointers and references. Since you have a vector<Tool>, you lose polymorphism. To retain it, store a vector<Tool*>. Even better, store a vector<unique_ptr<Tool>>.
Assigning a derived class object to a base class is called object slicing. You do lose information contained in the derived object. This is the case when you are inserting a Computer into a vector<Tool>.
I have the code:
#include <iostream>
#include <cstdlib>
using namespace std;
class Animal{
private:
int age;
public:
Animal() : age(1) {}
void toString(){
cout << "Age: " << age << endl;
}
};
class Cat : public Animal
{
public:
Cat() : age(5) {}
/*
void toString(){
cout << "Age: " << age << endl;
}*/
private:
int age;
};
int main(){
Cat tom;
tom.toString();
system("pause");
return 0;
}
But when I run the program, the age of the tom variable is 1, not 5. Does the toString can not read the age variable? If we open the /* */ the toString method in the Cat class, the age will be 5 !
(My english is not good very much. Thanks)
The problem is that Cat is writing to the age variable in Cat, while toString() reads the age variable in Animal, which, with Animal's constructor, is initialized to 1.
To solve this, you can provide another constructor for Animal which accepts an age parameter which is used to initialize Animal's age member variable.
class Animal{
private:
int age;
public:
Animal() : age(1) {}
Animal(int param_age) : age(param_age) {} // Initialize member variable age with parameter
void toString(){
cout << "Age: " << age << endl;
}
};
class Cat : public Animal
{
public:
Cat() : Animal(5) {} // Call Animal's constructor that set's the age
};
UPDATE: Another solution is to add a setter method in Animal class that sets its age. You can then call it in Cat's constructor to set the proper age.
class Animal{
private:
int age;
public:
Animal() : age(1) {}
void setAge(int age) { this->age = age; }
void toString(){
cout << "Age: " << age << endl;
}
};
class Cat : public Animal
{
public:
Cat() {
setAge(5);
}
};
Yet another alternative is to make Animal's age member protected
class Animal{
protected: // THIS
int age;
public:
Animal() : age(1) {}
void toString(){
cout << "Age: " << age << endl;
}
};
And remove Cat's age variable in the class definition. Despite its simplicity, this approach gives you more risk in encountering the "brittle base class" problem. Thus, I recommend the former solution as it is less prone to the said problem, and IMHO better sticks to the "write against interfaces, not implementations" principle.
The problem is that you are setting Cat::age in the Cat constructor, not the Animal::age used by Animal::toString.
Change the visibility of Animal::age to protected.
class Animal {
protected:
int age;
public:
Animal() : age(1) {}
void toString(){
cout << "Age: " << age << endl;
}
};
Don't redeclare a second age (which becomes Cat::age). Instead, change the value of age (Animal::age).
class Cat : public Animal {
public:
Cat() {
age = 5;
}
};
Try:
#include <iostream>
#include <cstdlib>
using namespace std;
class Animal{
private:
int age;
public:
Animal(int a = 1) // Pass in the age as a parameter.
: age(a) // Default to 1.
{}
// Prefer generic print function rather than toString()
friend std::ostream& operator<<(std::ostream& s, Animal const& a) {
return s << "Age: " << a.age << '\n'; // Prefer '\n' rather than endl
// Unless you really want to flush
// the stream (this is not usually
// the case).
}
};
class Cat : public Animal
{
public:
Cat()
: Animal(5) // Now you can call the base class constructor
{} // And get it to set 5
private:
// int age; // don't have a private copy here.
// use the one that is available in the base class.
// Prefer generic print function rather than toString()
friend std::ostream& operator<<(std::ostream& s, Cat const& a)
{
// Print Cat
// Then use the Animal priting function to print more information about the object.
return s << "A Cat: " << static_cast<Animal const&>(*a);
}
};
int main(){
Cat tom;
// tom.toString(); // Don't use a toString() method.
// overload operator<< to print to a stream.
// If you want to convert to a string the just print
// to a string stream.
std::cout << tom;
system("pause");
return 0;
}