I am using pure virtual functions and interfaces for the first time but having some troubles, probably because i did not fully understand some of the basics.
In the main function, i am trying to create an object "a" of a derived class which is creating another object "obj" inside the class and sets a member variable of obj to some value.
Later in the main function, i want to print the member variable of obj.
The Error class "AbstractB" has no member "setVar" occurs in DerivedA.h .
The setVar function is not part of the abstract class because in different derived classes var may have different data types.
AbstractA.h
class AbstractA
{
public:
AbstractA() {}
virtual ~AbstractA() {}
virtual void buildObj() = 0;
AbstractB* getObj() { return obj; }
protected:
AbstractB* obj;
};
AbstractB.h
class AbstractB
{
public:
AbstractB() {}
virtual ~AbstractB() {}
virtual void doSthWithVar() = 0;
// All derived classes have a private member variable var of varying data types
};
DerivedA.h
class DerivedA: public AbstractA
{
public:
// buildObj() creates some numbers e.g. 1
void buildObj() { obj->setVar( 1 ); } // Error due to calling the function using the abstract class instead of the derived one
};
DerivedB.h
class DerivedB
{
public:
void setVar( int i ) { var = i; }
void doSthWithVar(){ std::cout << var << std::endl; }
private:
int var;
};
main.cpp
int main()
{
DerivedA a;
a.buildObj(); // Creating a DerivedB object which is holding a variable var
// I want to do something like this
AbstractB* obj = a.getObj();
obj->doSthWithVar(); // Should print 1
}
Is there any way to call the setVar() function in DerivedA.h to allow later retrieval of var without disturbing the structure of the abstract classes?
EDIT:
I implemented the solution from Robert Andrzejuk in the following way:
class DerivedA: public AbstractA
{
public:
void buildObj()
{
DerivedB* b = new DerivedB();
b->setVar( 1 );
obj = b;
}
};
I don't see where You have created an instance of DerivedB?
The most logical place looks like in DerivedA.
And that's where You have all the info to call the needed functions.
class DerivedA: public AbstractA
{
DerivedB b;
public:
// buildObj() creates some numbers e.g. 1
void buildObj()
{
b.setVar( 1 );
obj = &b;
}
};
Related
For example, I have 2 classes (in reality, it's more, that's why I'm asking this question) with the same methods:
class class1{
public:
void init(){
//something
}
void dostuff(){
//something
}
//
};
class class2{
public:
void init(){
//something
}
void dostuff(){
//something
}
//
};
And now a third one in which I want to deal with the two classes in the same manner:
class upclass{
public:
upclass(class12* argclass){
myclass=argclass;
myclass->init();
}
void domorestuff(){
myclass->dostuff();
}
private:
class12* myclass; //pointer to class 1 OR class 2
};
My question is now, do I need multiple constructors and multiple declarations to make it work or is there a way around it? Is it even possible to make "class12" a spacekeeper for these types without preprocessor-directives?
I am sorry to say, this is a wide field and there are really many many possible solution.
But I guess that we are talking about object- oriented programming, derivation and plymorphic functions. What you describe, will be typically solved with a class hierachy.
You have one base class with virtual (polymorphic) functions.
Then you derive other classes from this base class and override the virtual functions from the base class.
In a 3rd step, you create some instances of the derived classes dynamically, during runtime and you store the newly created classes (their address) in a pointer to the base class.
Later, you can call any of the virtual overriden function through the base class pointer. And mechanism behind the scenes will call the correct function for you.
Additionally. You defined some function init. Such a function name suggests the usage of a class-constructor. This will be called automatically in the correct sequence. First the base class constructor and then the derived class constructor.
Please see the below example:
#include <iostream>
#include <string>
class Base {
std::string baseName{};
public:
Base() { // Do initialization stuff
baseName = "Base";
std::cout << "\nConstructor Base\n";
}
virtual void doStuff() { // virtual function
std::cout << baseName << '\n';
}
};
class Derived1 : public Base {
std::string derivedName{};
public:
Derived1() : Base() { // Do initialization stuff
derivedName = "Derived1";
std::cout << "Constructor Derived1\n";
}
void doStuff() override { // Override virtaul function
std::cout << derivedName << '\n';
}
};
class Derived2 : public Base {
std::string derivedName{};
public:
Derived2() : Base() { // Do initialization stuff
derivedName = "Derived2";
std::cout << "Constructor Derived2\n\n";
}
void doStuff() override { // Override virtaul function
std::cout << derivedName << '\n';
}
};
int main() {
Base* base = new Base();
Base* derived1 = new Derived1(); // Store in base class pointer
Base* derived2 = new Derived2(); // Store in base class pointer
base->doStuff();
derived1->doStuff(); // Magic of polymorphism
derived2->doStuff(); // Magic of polymorphism
}
The Base class pointer will accept all classes derived from Base.
Please note. In reality you ould not use raw pointers and also to the constructor differently. This is just fotr demo.
But, you need to read several books about it to get the complete understanding.
You can explicitly write "store one of these" via std::variant and obtain the actual type (when needed) through std::visit:
#include <variant>
using class12 = std::variant<class1*, class2*>;
class upclass {
public:
upclass(class12 argclass): myclass{argclass} {
visit([](auto classn) { classn->init(); }, myclass);
}
void domorestuff() {
visit([](auto classn) { classn->dostuff(); }, myclass);
}
private:
class12 myclass;
};
If those visits get too repetitive, you might consider writing a pretty API to hide them:
class prettyclass12: public std::variant<class1*, class2*> {
private: // both g++ and clang want variant_size<>, a quick hack:
auto& upcast() { return static_cast<std::variant<class1*, class2*>&>(*this); }
public:
using std::variant<class1*, class2*>::variant;
void init() { visit([](auto classn) { classn->init(); }, upcast()); }
void dostuff() { visit([](auto classn) { classn->dostuff(); }, upcast()); }
};
class prettyupclass {
public:
prettyupclass(prettyclass12 argclass): myclass{argclass} { myclass.init(); }
void domorestuff() { myclass.dostuff(); }
private:
prettyclass12 myclass;
};
I'm working on a small project, and I found myself in a situation like this :
class A{}
class B : class A {
public:
void f();
int getType() const;
private:
int type;
}
class C : class A{
public:
int getType() const;
private:
int type;
}
I want to know if there's a way to call the f() function (in class B) from an object of type A?
I tried this but it says function f() cannot be found in class A :
int main(){
vector<A*> v;
// v initialized with values of A ...
if (v->getType() == 1){ // 1 is the type of B
v->f();
}
}
As you've seen, this code won't compile because A doesn't have an f method. In order to make it work, you'd have to explicitly downcast the pointer:
B* tmp = dynamic_cast<B*>(v);
tmp->f();
To begin with, with your current classes, you can't call getType() on an A*. Because the interface of A doesn't have this method. To solve this problem, you either need to make getType a virtual function in A, or move the type field to base class A (as protected) and initialize it in the constructors of the child classes. Let me show you the first method, because I think it is a better approach, since it makes the objective of this function more clear.
class A {
public:
virtual int getType() { return 0; } // or delete the function: ... getType() = 0;
}
class B : public A {
public:
int getType() override { return 1; }
}
With these classes, once you create an instance of B, getType() returns 1 when called on that instance, whether it is pointed to by an A* or B*:
A *object = new B();
object->getType(); // returns 1
Now, if you need to access the f() from B, you can again add it as a virtual method to A's interface, or make a cast to B*.
Using a virtual method:
class A {
public:
virtual void f() { /* a default action maybe? */ }
}
class B : public A {
public:
void f() /* override if you want */ { /* whatever this function does in B */ }
}
...
for (A *ptr : v)
ptr->f();
Using a cast:
class A {
public:
virtual int getType() { return 0; }
}
class B : public A {
public:
void f();
int getType() override { return 1; }
}
...
for (A *ptr : v)
if (ptr->getType() == 1)
dynamic_cast<B*>(ptr)->f();
I have an abstract class Job and other classes that implement it like:
Waiter and Builder, all of them implement my function in the same way.
For example:
Waiter::changeScore()
{
score += top_score;
}
How may I prevent this kind of code duplication?
Constraints:
I want to keep Job abstract.
Each Waiter or Builder has its own top_score value (It differs between classes and objects of the same class).
Not all member functions of an abstract class need to be pure virtual (as long as at least one is). Your changeScore member is an ideal candidate as a 'real' base class function. Further, not only does it not need to be pure virtual, it doesn't even need to be virtual at all (unless you want your polymorphism to change what a pointer to a derived class will see, for that function).
As each class (or object) will have its own value of top_score (as you have stated), then that (data) member can also be part of the 'abstract' base class.
You can even add a single 'dummy' pure virtual function in your base class (which is never intended to be used, even by a derived class), just to make sure that instances aren't accidentally created. For example, your Job class could have a member:
virtual int Dummy() = 0;
Then, any derived class must have an override for that (however trivial), or the compiler won't allow you to declare an instance of that class. So, your Waiter class would need something like:
int Dummy override { return 1; }
The following code sample may help/demonstrate the idea:
#include <iostream>
#include <memory> // So we can use smart pointers
class Job {
public:
int score{ 0 }, top_score{ 0 };
public:
Job() { }
virtual ~Job() = default;
virtual void Dummy() = 0; // This is sufficient to make the class abstract!
void changeScore() {
score += top_score;
}
virtual void showName() {
std::cout << "Generic Job" << std::endl;
}
};
class Waiter : public Job {
public:
Waiter(int top = 5) { top_score = top; }
~Waiter() override = default;
void Dummy() override { } // We need this in order to use Waiter
void showName() override {
std::cout << "Waiter" << std::endl;
}
};
class Builder : public Job {
public:
Builder(int top = 10) { top_score = top; }
~Builder() override = default;
void Dummy() override { } // We need this in order to use Builder
void showName() override {
std::cout << "Builder" << std::endl;
}
};
int main()
{
Waiter w{ 6 }; // OK - uses explicit value for 'top' parameter
Builder b; // OK - uses default value for 'top' parameter
// Job j; // ERROR - Cannot instantiate abstract class
w.changeScore();
b.changeScore();
std::cout << w.score << std::endl;
std::cout << b.score << std::endl;
// Also, using pointers...
// Job* pj = new Job; // ERROR - Cannot instantiate abstract class
Job* pw = new Waiter; // OK - Now we can make use of polymorphism...
Job* pb = new Builder; // ...with either of these 2 "Job" pointers!
pw->showName();
pb->showName();
delete pw;
delete pb;
// Polymorphism also works with smart pointers (which you SHOULD be using) ...
// std::unique_ptr<Job> upj = std::make_unique<Job>(); // ERROR - Allocating an object of abstract class
std::unique_ptr<Job> upw = std::make_unique<Waiter>(15);
upw->changeScore();
std::cout << upw->score << ": ";
upw->showName();
std::unique_ptr<Job> upb = std::make_unique<Builder>(42);
upb->changeScore();
std::cout << upb->score << ": ";
upb->showName();
return 0;
}
You can define the method in the base class:
Live demo
class Job {
private:
int score;
int top_score;
protected:
//protected constructor to be inherited by derived classes
Job(int top_score) : top_score(top_score) {}
//one pure virtual method is enough to make the class abstract
virtual void some_method() = 0;
public:
void changeScore() { //single method implementation
score += top_score;
}
//to use polymorphism you must use a virtual destructor, unless you use shared_ptr
virtual ~Job(){}
};
class Waiter : public Job {
public:
Waiter(int top_score) : Job(top_score) {}
// pure virtual methods must be overridden in all derived classes
void some_method() override{}
};
class Builder : public Job {
public:
Builder(int top_score) : Job(top_score) {}
void some_method() override{}
};
changeScore() will be implemented in the abstract class and will be usable by all derived classes.
Waiter w(10); //top_score 10
Buider b(20); // top_score 20
b.changeScore();
w.changeScore();
You can make the changeScore method a pure virtual method AND provide an implementation. This would look like this:
class Job {
int score{0};
int top_score{0};
public:
virtual void changeScore() = 0;
};
void Job::changeScore()
{
score += top_score;
}
Then you can call the changeScore method of the Job base class in the child classes like this:
class Waiter : public Job {
public:
virutal void changeScore() override {
Job::changeScore();
}
};
This way if you want to change changeScore, you do not need to change all the implementations in the child classes, but you can just change the implementation in the Job class.
This way you do not need any dummy methods and the Job class remains abstract, while the override in the child classes is trivial and you have a single implementation if you ever want to change it.
EDIT:
If you are wondering where this override keyword comes from, it is introduced in C++11. Since I do not know which C++ version you are using I just wanted to point that out.
You can read about the override specifier here
EDIT II:
Regarding that ever child class has its own top_score, you should set this via the constructor of those child classes.
Like this:
class Job {
protected:
int top_score{0};
Job(top) : top_score(top) {}
...
};
class Waiter : public Job {
public:
Waiter(int top): Job(top) {}
...
};
This way each child class has its own version of top_score
EDIT III:
Putting it all together the classes would look something like this:
class Job {
protected:
int score{0};
int top_score{0};
Job(top) : top_score(top) {}
public:
virtual void changeScore() = 0;
};
void Job::changeScore()
{
score += top_score;
}
class Waiter : public Job {
public:
Waiter(int top): Job(top) {}
virutal void changeScore() override {
Job::changeScore();
}
};
I have a base class. For example:
class CData{
public:
CData(const std::string &_filename)
{
m_filename = _filename;
// LodaData(); // wrong
}
virtual void LoadData() = 0;
private:
std::string m_filename;
};
And, a subclass:
class COtherData: public CData{
public:
COtherData(const std::string &_filename): CData(_filename) {}
virtual void LoadData() {
// some code to load data
...
}
};
I want to know how to perform some tasks in base class for subclasses.
The problem is that you call virtual function from constructor - you should avoid it. Instead you need to add a function to the base class that will call your virtual functions, which eventually end up with calling overridden function of the child class.
Thus I will change your base class in the following way:
class CData
{
public:
CData(const std::string &_filename)
: m_filename(_filename)
{}
void performTask()
{
LoadData();
// ... do something else
}
virtual void LoadData() = 0;
private:
std::string m_filename;
};
Create different constructors in the base class, then in the subclass call the appropriate constructor. Or use default arguments that change appropriately.
class A
{
A(int a = 0)
{
if(a == 0) // first case
else // second case
}
};
class B : public A
{
B() : A(0) {} // First case
--- or ---
B() : A(1) {} // Second case
}
I've got some problems with my lamba expressions: I have a class that owns a function pointer.
class SomeClass
{
void (*execFunc)(Base*);
}
And I have a Base class:
class Base
{
SomeClass* someClass;
void doSomething() { someClass->execFunc(this); }
}
From this one I derive lots of other classes whose execFuncs will be different. Therefore I want to use lambda-expressions; e.g:
class Derived final : public Base
{
int someDerivedAttrib;
static List<SomeClass*> someClasses = createSomeClasses(); // holds all possible
// SomeClasses for this
// derived class
static List<SomeClass*> createSomeClasses()
{
List<SomeClass*> scs;
SomeClass* sc = new SomeClass();
sc->execFunc = [] (Derived* derived) { derived->someDerivedAttrib = 10; };
scs << sc;
return scs
}
}
But unfornately this won't work since cast from void (*)(Derived*) to void (*)(Base*) is not possible. Any suggestions, except making a cast form Base* to Derived* in every lambda-function?
Expecting ye answers,
Albjenow
How about, instead of SomeClass being a regular class, making it a the base class of a class template that handles having the proper functor type, as well as downcasting to the right type ?
It would look like this:
class SomeClass
{
virtual void callFunc(Base*) = 0;
}
template<typename T>
class SomeDerivedClass : public SomeClass
{
static_assert(std::is_base_of<Base, T>::value, "SomeDerivedClass: unexpected base class");
virtual void callFunc(Base* b) override
{
execFunc(static_cast<T*>(b));
}
void (*execFunc)(T*);
}
Base then becomes:
class Base
{
SomeClass* someClass;
void doSomething() { someClass->callFunc(this); }
}
Then, in your Derived definition:
class Derived final : public Base
{
int someDerivedAttrib;
typedef SomeDerivedClass<Derived> tSomeClass;
static List<tSomeClass*> someClasses = createSomeClasses(); // holds all possible
// SomeClasses for this
// derived class
static List<tSomeClass*> createSomeClasses()
{
List<tSomeClass*> scs;
tSomeClass* sc = new tSomeClass();
sc->execFunc = [] (Derived* derived) { derived->someDerivedAttrib = 10; };
scs << sc;
return scs
}
}
However, this runs the risk of calling SomeDerivedClass::call with the wrong concrete class.
Wouldn't this do the trick?
sc->execFunc = [] (Base* base) { static_cast<Derived*>(base)->someDerivedAttrib = 10;
After all you have to respect the original signature of the execFunc pointer.