Click here to Skip to main content
15,881,679 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello,

I am moving from c# to c++ and I am having a little trouble adjusting.


I know the code below would through a whole bunch of errors, buts its the general idea
behind what I am trying to do.

class base
{

};

class deriven1 : public base
{

 public:
   int getint() {return num}

 private:
   int num;

};


class deriven2 : public base
{
public:
   string getstr() {return str}

 private:
   string str;
};


int main()
{
  base b = get_deriven_1_or_2();



  if(b is deriven1)
   {
     deriven1 d1 = (deriven1)b;
      
     int i = d1.getint();
     //do stuff

   }
  if(b is deriven2)
   { 
     deriven2 d2 = (deriven2)b;
     string s = d2.getstr();
     //do stuff


    }

}



so basically I am trying to change from a deriven to a base back to a deriven with out losing any data.

I had a c# program that did something like it but I have no clue how to do it in c++, so any help would be greatly appreciated!
Posted
Comments
Sergey Alexandrovich Kryukov 6-Jul-11 14:10pm    
"Derived".
--SA
me3344 6-Jul-11 14:57pm    
I was using the derived classes so that I could have one variable (base) that accepted multiple types without knowing which type it would be.

If we're talking about unmanaged C++, you can do this:

C++
class deriven3 : public deriven1, deriven2
{
}


and then you can get to both the string property and the int property, like so:

C++
int x = d3.getint();
string y = d3.getstr();


If we're talking about managed C++, you have to create interfaces because multiple class inheritence is not supported. However, you can inherit from one class and one or more interfaces.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 6-Jul-11 14:30pm    
This is one of the valid ideas (my 5), but I cannot be sure this is what OP needs. What she/he really needs is rather some basic OOP education.

Please see my answer.
--SA
This code will not even compile. For example ';' terminators after operators are missing. If you need better answers, please check up your code using a real compiler.

Now, what you do 1) is irrelevant to the differences between C#, C++ (which you're trying to use here) or C++/CLI; 2) you code is not object-oriented at all; consider you do not have classes at all, the quality of your code will be exactly the same.

When you use object-oriented approach you use type case and operator "is" or "as" very rarely. In C++, there is no such operators, but the dynamic typecast is available in the form of dynamic_cast<>, see http://en.wikipedia.org/wiki/Dynamic_cast[^].

Now, that said, even in C# you did not know how to use OOP. The idea of using derived class is providing a base class which represent the common interface for the hierarchy and using virtual methods and overriding to provide late binding, see http://en.wikipedia.org/wiki/Late_binding[^]. You should know the difference between compile-time and run-time types. The idea is using some base type as a compile-time type for a variable, but instantiate one of derived types.

The construct working as a .NET interface in C++ (not C++/CLI) is represented by the class having no data and only pure-virtual functions, see http://en.wikipedia.org/wiki/Pure_virtual_method#C.2B.2B[^] and the section "Abstract classes and pure virtual functions".

There is a lot more to it. I suggest you take a good manuals for OOP in C#, C++/CLI, .NET and C++ (pick just one for starters) and learn how OOP really works. You will really need it.

You also have some change to get a practical advice in your particular case, but in this case you will need to explain your ultimate goal. In your follow-up question, please do not use the much of the notion of the class (you don't really know what is it — just yet) but focus more on the application aspects.

Good luck,
—SA
 
Share this answer
 
Comments
#realJSOP 6-Jul-11 14:36pm    
Casting won't address it. If you have two objects derived from a common base class, unless the properties you want to access are in the base class, and properties are set according to the reuqirements, casting a class1 to class2 won't give him access to any properties not defined/implemented in class2. The best thing to do is to add the appropriate functionality (via operator overloading, and/or constructors) that allow him to exhange data between the two objects. As you stated, his goals haven't been declared, so we really can't give him concrete advice.
Sergey Alexandrovich Kryukov 6-Jul-11 14:39pm    
Sure, you're absolutely right. As I pointed out, in real OOP approach, casting should be used very rarely (better not used at all). I put information on the dynamic_cast<> just for completeness, not as if I recommended it.
--SA
Generally speaking, in standard, unmanaged C++ there's no way to tell them apart, since they're just pointers. That's one of the advantages of using object oriented programming, polymorphism, but its up to the designer to keep track of the type of objects that his derived classes can become.

John's solution is nice, but there's other ways to keep track, just have to be a bit inventive.
class base
{
 protected:
 int m_type;
 
 public:
 base(){m_type=0;}
};
class derived1 : public base
{
 public:
 derived1(){m_type=1;}
}
class derived2 : public base
{
 public:
 derived2(){m_type=2};
}


You can even add an enumerated list of supported types in the base.
class base
{
 enum TYPE{BASE =0, DER1, DER2, DER_MAX=DER2};

 protected:
 TYPE m_type;

 public:
 base(){m_type=BASE;} //And just define the others accordingly
};


...and I agree with SA, the whole point of using derived classes is that they share the same common methods.
 
Share this answer
 
v2
Comments
Emilio Garavaglia 6-Jul-11 15:28pm    
The idea is not itself bad, but it is just "reinventing RTTI", that is already part of the language.
Just give to base a virtual method (a do-noting virtual destructor is enough) and let dynamic_cast check if a pointer can runtime become another or not.
It gives identical result, but let the compiler able -if it is- to optimize out the whole structure.
Albert Holguin 6-Jul-11 19:05pm    
...true... but wouldn't dynamic casting be a whole hell of a lot more inefficient (since it compares everything instead of just a variable)? ..but regardless, good point...
Emilio Garavaglia 7-Jul-11 2:19am    
It depends of how smart is the compiler implementation. Checking if a supposed derivation is true just requires a comparison of vtable POINTERS (not tables!). That's the same as comparing integers.
What you're describing sounds like Variants, i. e. a class that serves as a wrapper for variables of varying type. You can implement these without classes, using union, or google for existing implementations and use those. I believe Managed C++ even has such a class, but I'm not working with that, so I may be wrong.

Solution with union:
struct SVariant {
   enum { VAR_DOUBLE, VAR_INT } vartype;
   union {
      double x;
      int i;
   } value;
};
void setVariant(SVariant* v, double value) {
   v.value.x = value;
   v.type = VAR_DOUBLE;
}
void test(SVariant* v) {
   if (v.type == VAR_DOUBLE) {
       do_double(v.value.x);
   else if (v.type == VAR_INT) {
       do_int(v.value.i);
   }
}


Anyway, in most cases Variants are a bad idea: they place the onus of distinguishing the actual types and deciding what to do with the values on the caller. It is exactly the opposite of what OO-design is about, and so I feel it's wrong to even try and create a class framework for such a concept.

What you should do is create a class for each type of variable, and then put the functions that operate on the values into these classes! You could implement it like this:
// file CBase.h
class CBase {
public:
   virtual ~CBase(); // always define a virtual destructor on a base class!
   virtual void do_work() = 0; // '=0' makes this a 'pure' virtual function
};

// file CDerived1.h
class CDerived1 : public CBase {
private:
   double x_;
public:
   CDerived1(double x);
   ~CDerived1(); // always define the destructor on a derived class!
   void do_work(); // pure virtual functions must be overridden
};

// file CDerived2.h
class CDerived2 : public CBase {
private:
   int i_;
public:
   CDerived2(int i);
   ~CDerived2();
   void do_work();
};

// file CDerived1.cpp
CDerived1::CDerived1(double x) : x_(x) {
}
void CDerived1::do_work() {
   do_double(x_);
}

// file CDerived2.cpp
CDerived2::CDerived2(int i) : i_(i) {
}
void CDerived2.do_work() {
   do_int(i_);
}

// file test.cpp
void test(CBase* b) {
   b->do_work();
}

void main_test() {
   CDerived1 d1(3.14);
   CDerived2(42);
   test(d1); // calls do_double(3.14)
   test(d2); // calls do_int(42)
}

In this solution, the caller test() just calls do_work(), and that's it. it doesn't need to know what derived classes exist, and what to do with each value, the implementation of each derived class does it for you. The caller doesn't even need to know there *are* any derived classes, although the '=0' in this example is a dead giveaway.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900