New to Cpp. In the given code, I don't know what change_val(int k) = 0;
means and why the compiler prints
error: cannot declare variable 'ob1' to be of abstract type 'B'
B ob1(10);
error: invalid new-expression of abstract class type 'B'
ob2 = new B(100);
To my knowledge, neither B
nor A
has been declared abstract. Then why can't I declare a variable of B object? And is it possible to assign object of one class to another object type as in A *ob2; ob2 = new B(100);
?
The code:
#include<iostream>
using namespace std;
class A{
int x;
public:
A(){x=0;}
explicit A(int x){ cout<<"Constructor of A called"<<endl;
this->x = x 100;}
virtual void change_val(int k) = 0;
void set_x(int k){x = k;}
int get_val() const{ return x; }
virtual void print_value()
{
cout<<x<<endl;
}
};
class B : public A{
public:
explicit B(int k):A(k){
cout<<"Constructor of B called"<<endl;
}
void print_value() override
{
cout<< get_val() 200<<endl;
}
};
int main(){
B ob1(10);
ob1.print_value ();
A *ob2;
ob2 = new B(100);
ob2->print_value ();
ob2->change_val(20);
ob2->print_value ();
}
CodePudding user response:
We'll start with a quick review of your code:
#include<iostream>
using namespace std; // Bad practice
class A{
int x;
public:
A(){x=0;} // Bad practice; utilize default member initialization
explicit A(int x){ cout<<"Constructor of A called"<<endl; // Bad practice; utilize initialization section
this->x = x 100;} // Poor style throughout this code
// Missing virtual destructor
virtual void change_val(int k) = 0; // Pure virtual function, makes A an abstract class
void set_x(int k){x = k;}
int get_val() const{ return x; }
virtual void print_value()
{
cout<<x<<endl; // Prefer '\n' over std::endl
}
};
class B : public A{
public:
explicit B(int k):A(k){ // Why use initialization here but not above?
cout<<"Constructor of B called"<<endl;
}
void print_value() override
{
cout<< get_val() 200<<endl;
}
// Failed to override pure virtual function change_val(), making B abstract as well
};
int main(){
B ob1(10);
ob1.print_value ();
A *ob2;
ob2 = new B(100); // Initialize on same line as declaration
ob2->print_value ();
ob2->change_val(20);
ob2->print_value ();
// Missing delete
}
This is subjective, so I didn't note it above, but it's also possible for the member x
to be protected in A
so that B
can directly access it instead of going through a getter. My code below does this. I see no reason to make implementing children classes more difficult.
#include <iostream>
// using namespace std; // Bad practice
class A {
protected:
int x = 0;
public:
A() = default;
virtual ~A() = default;
explicit A(int x) : x(x 100) { std::cout << "A ctor" << '\n'; }
// Pure virtual function, makes A abstract
virtual void change_val(int k) = 0;
void set_x(int k) { x = k; }
int get_val() const { return x; }
virtual void print_value() { std::cout << x << '\n'; }
};
class B : public A {
public:
explicit B(int k) : A(k) { std::cout << "B ctor" << '\n'; }
// Simpler function due to x being protected now in A
void print_value() override { std::cout << x 200 << '\n'; }
// Overriding the pure virtual function makes B a concrete class now
void change_val(int k) override { x = k; }
};
int main() {
B ob1(10);
ob1.print_value();
A *ob2 = new B(100);
ob2->print_value();
ob2->change_val(20);
ob2->print_value();
delete ob2;
}
Output:
❯ ./a.out
A ctor
B ctor
310
A ctor
B ctor
400
220
I noted that a virtual destructor was missing. It's important to have this for all base classes so that your derived objects can be properly destroyed.
You also called new
without a subsequent delete
. In bigger programs doing actual work, this would have leaked memory. To avoid this issue, you could use std::unique_ptr
from <memory>
. It handles the creation and destruction for you.
#include <memory>
/*
* Your code
*/
int main() {
B ob1(10);
ob1.print_value();
std::unique_ptr<A> ob2(new B(100));
ob2->print_value();
ob2->change_val(20);
ob2->print_value();
}
CodePudding user response:
To my knowledge, neither B nor A has been declared abstract.
In c there is no abstract
keyword (like in Java, for example) or declaration. The compiler decides for you whether the class is abstract using its definition. In c the class is abstract, if it contains one or more pure virtual methods (that = 0;
thing after method signature).
So, A
is implicitly declared as abstract (it has pure virtual method change_val()
). B
extends A
and overrides the print_value()
method. However, it does not implement the change_val()
method, so it is implicitly declared as abstract too.
So it is easy to understand the errors your compiler generated.
error: cannot declare variable 'ob1' to be of abstract type 'B'
B ob1(10);
That happens because you try to instantiate an instance of abstract class B
. It is impossible in other languages too.
The explanation for the second error is the same.
error: invalid new-expression of abstract class type 'B'
ob2 = new B(100);
You are trying to instantiate B
which is an abstract type (sometimes called incomplete type
).
And is it possible to assign object of one class to another object type as in A *ob2; ob2 = new B(100);?
If you create class C
which inherits B
and implements the change_val()
method, so the class is not abstract anymore, it is possible to say for example:
class A{
int x;
public:
A(){
x=0;
}
explicit A(int x) {
cout << "Constructor of A called" << endl;
this->x = x 100;
}
virtual void change_val(int k) = 0;
void set_x(int k) {
x = k;
}
int get_val() const {
return x;
}
virtual void print_value() {
cout << x << endl;
}
};
class B : public A {
public:
explicit B(int k): A(k) {
cout << "Constructor of B called" << endl;
}
void print_value() override {
cout << get_val() 200 << endl;
}
};
class C : public B {
public:
explicit C(int number) : B(number) {
cout << "Constructor of C called" << endl;
}
void change_val(int number) override {
set_x(number);
}
};
int main() {
A* obj = new C(100);
obj->change_val(200);
obj->print_value();
}
The following program will output 400
.