I'm trying to become accustomed to classes. Here I've made a base class called Animal and a derived class called Dog.
I was originally able to to get the base class to work alone, but when I tried adding a derived class, things got messy and I got errors. Here is the code, and if you could let me know what I'm doing wrong, that'd be great!
#include <iostream>
#include <string>
using namespace std;
class Animal{
protected:
int height, weight;
string name;
public:
int getHeight() { return height; };
int getWeight() { return weight; };
string getName() { return name; };
Animal();
Animal(int height, int weight, string name);
};
Animal::Animal(int height, int weight, string name){
this->height = height;
this->weight = weight;
this->name = name;
}
class Dog : public Animal{
private:
string sound;
public:
string getSound() { return sound; };
Dog(int height, string sound);
};
Dog::Dog(int height, string sound){
this->height = height;
this->sound = sound;
}
int main()
{
Animal jeff(12, 50, "Jeff");
cout << "Height:\t" << jeff.getHeight << endl;
cout << "Weight:\t" << jeff.getWeight << endl;
cout << "Name:\t" << jeff.getName << endl << endl;
Dog chip(10, "Woof");
cout << "Height:\t" << chip.getHeight() << endl;
cout << "Sound:\t" << chip.getSound() << endl;
}
The default constructor for the Animal class is not defined. You need:
Animal::Animal() : height(0), weight(0) // Or any other desired default values
{
}
You should also have a virtual destructor on the base class.
class Animal
{
public:
~Animal() {} // Required for `Animal* a = new Dog(...); delete a;`
// deletion via base pointer to work correctly
};
Edit:
Upon removal of Animal() I get an error that says 'Animal': no appropriate default constructor available
You need to implement the default constructor (see above). Without it the int members will not be initialized and have undefined values.
Related
I have a class derived from base class, and set constructors for each classes, but I keep getting error that I do not have any constructor for base class.
class Dog
{
protected:
string name;
int age;
public:
Dog(string dogsName, int dogsAge)
{
name = dogsName;
age = dogsAge;
}
virtual void Bark()
{
cout << "Woof Woof I am a dog" << endl;
}
class Huey: public Dog
{
public:
Huey()
{
name = "goodboy";
age = 13;
}
void Bark()
{
cout << "woof" << endl;
}
}
Here I get an error on Huey() and it says " no default constructor exists for 'Dog'". But I think I have created a constructor for class Dog. Can you please explain why this code is wrong?
When you specify any constructor of your own, the default constructor is not created anymore. However, you can just add it back.
class Dog
{
protected:
string name;
int age;
public:
Dog() = default;
Dog(string dogsName, int dogsAge)
{
name = dogsName;
age = dogsAge;
}
virtual void Bark()
{
cout << "Woof Woof I am a dog" << endl;
}
};
class Huey: public Dog
{
public:
Huey()
{
name = "goodboy";
age = 13;
}
void Bark()
{
cout << "woof" << endl;
}
};
EDIT: It seems like you want to call your custom Dog constructor from Huey. It is done like so
class Dog
{
protected:
string name;
int age;
public:
Dog(string dogsName, int dogsAge)
{
name = dogsName;
age = dogsAge;
}
virtual void Bark()
{
cout << "Woof Woof I am a dog" << endl;
}
};
class Huey: public Dog
{
public:
Huey() : Dog("goodboy", 13) {}
void Bark()
{
cout << "woof" << endl;
}
};
You need to create a constructor with no parameters and no implementation. As below:
public:
Dog() = default;
Two ways:
1) have a default constructor with no params.
2) call the existing constructor you have in Dog from Huey ( this is the right thing in your case since Huey is a Dog after all). Huey is currently calling the default constructor of Dog since this isn’t defined and explicitly called.
I was just revising the basic concepts of OOP and I ran across this. The program works but I can not understand why it works. I have a base class Vehicle and child class Car and Grandchild class TwoDoorCar. The code is given below:
class Vehicle {
private:
int wheels;
string make;
protected:
int protect;
public:
virtual ~Vehicle(){}
Vehicle(){
cout << "empty Vehicle constructor" << endl;
this->wheels = 0;
this->make = "";
this->protect = 0;
}
Vehicle(int wheel,string m){
cout << "parametrized Vehicle constructor" << endl;
this->wheels = wheel;
this->make = m;
this->protect = 0;
}
void ctest() const{ // read only function
cout << "ctest() called" << endl;
}
virtual void Drive() = 0;
const string& getMake() const {
return make;
}
void setMake(const string& make) {
this->make = make;
}
int getWheels() const {
return wheels;
}
void setWheels(int wheels) {
this->wheels = wheels;
}
};
class Car : virtual public Vehicle {
private:
int carNumber;
public:
virtual ~Car(){}
Car():Vehicle(){
cout << "empty car constructor" << endl;
carNumber = 0;
}
Car(int wheels, string make, int Number) : Vehicle(wheels,make){
cout << "Car's constructor called" << endl;
this->carNumber = Number;
}
Car(int wh, string m): Vehicle(wh, m){
this->carNumber = 0;
}
virtual void Drive(){
cout << "Car driven " << endl;
}
virtual void Drive(string p){
cout << "Over loaded function of Drive with string argument : " << p << endl;
}
void testProtect(){
cout << "Car::Protected member " << this->protect << endl;
}
};
class TwoDoorCar : public Car{
public:
virtual ~TwoDoorCar(){}
TwoDoorCar():Car(){
cout << "Empty two door car constructor" << endl;
}
TwoDoorCar(int wheels, string make, int reg) : Car(wheels,make,reg){
}
};
The pure virtual function Drive() is defined in the child class but not in the grandchild class. I tried using virtual in the child class, yet the program works with no function implementation of the Drive() function in the grandchild class.
I run with the following code
TwoDoorCar tdc1;
Vehicle * v3 = &tdc1;
v3->Drive();
The output of the program is
empty Vehicle constructor
empty car constructor
Empty two door car constructor
Car driven
Can anyone explain why there is no error here even though pure virtual and virtual are used in base and child class respectively?
Only pure virtual functions are required to be defined. virtual functions can be derived by inherited classes and does not require to be re-defined in inherited class.
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>.
Code:
#include <iostream>
#include <string>
using namespace std;
class Mammal {
public:
int age;
Mammal() {age = 55;}
void say() {
cout << "I'm a Mammal and my age " << age;
}
};
class Reptile {
public:
int age;
Reptile() {age = 77;}
void say() {
cout << "I'm a Reptile and my age " << age;
}
};
class Platypus: public Mammal, public Reptile {
public:
Platypus() :
Mammal(), Reptile() {
cout << "Constructed!" << endl;
}
};
int main() {
Platypus p;
p.Mammal::say();
p.Reptile::say();
}
And result is:
I'm a Mammal and my age 4215460
I'm a Reptile and my age 4215472
Why:
1. Platypus constructor wasn't called and "Constructor" wasn't output?
2. ages in parents are still random (parent constructors wasn't called too?)
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;
}