Можно ли с помощь полиморфизма реализовать разное содержание объекта?

Я хочу написать дерево со строго заданной глубиной, чтоб поле data находилось только на самом нижнем уровне дерево. Иными словами, я хочу реализовать две структуры ноды дерева, первая будет содержать только указатели на потомков, вторая, которая будет содержать указатели на потомков и поле data. Ниже пример.

struct Node1{
   Node1* left;
   Node1* right;
}

struct Node2{
   Node2* left;
   Node2* right;
   T data;
}

Можно ли добиться этого с помощью полиморфизма, если наследовать Node2 от Node1, то при создании Node2 через указатель на Node1 невозможно получить доступ к полю data, т.к поле data не содержится в Node1.


Ответы (1 шт):

Автор решения: AlexGlebe

В плюсах обычно делаются классами с виртуализацией.

class Node1 {
public :
   Node1* left;
   Node1* right;
   virtual bool hasData(){return false;}
};

class Node2 : public Node1 {
public :
   T data ;
   virtual bool hasData(){return true;}
} ;

И если hasData() вернул true , то делаете static_cast<Node2*>(p)->data чтобы достать данные.

Без виртуальных функций и наследования такое делается по другому :

struct Node1 {
   Node1* left;
   Node1* right;
   Node2 * son ;
} ;

struct Node2{
   Node1 base ;
   T data;
} ;

В данном примере Node2 - это наследник структуры Node1. Но чтобы добиться, что узел Node1 - это часть наследника Node2 придётся добавить ссылку на наследника. То есть сделать своими руками полиморфизм.

При конструкции простого узла создаётся структура Node1 с переменной son равным nullptr. А при создании Node2 в поле Node2.base.son = адрес данной структуры Node2;

Node2 n2 ;
n2 . base . son = & n2 ;

Создаёте дерево с узлами Node1 и проверяете son. Если son - не nullptr то это наследник Node2 и берёте данные .son->data.

Рабочий пример :

// g++ -std=c++11 -Wall -Wextra -Wpedantic poli.cpp -o poli && ./poli
# include <iostream>
class Node1 {
public :
   Node1* left;
   Node1* right;
   virtual bool hasData(){return false;}
};

template <class T>
class Node2 : public Node1 {
public :
   T data ;
   virtual bool hasData(){return true;}
} ;

template<class T>
struct sNode2;

template<class T>
struct sNode1 {
   sNode1<T>* left;
   sNode1<T>* right;
   sNode2<T> * son { nullptr } ;
   sNode1(){}
   sNode1(sNode2<T> * s):son{s}{}
} ;

template<class T>
struct sNode2{
   sNode1<T> base { this } ;
   T data;
} ;

int main(){
  Node1 n1;
  Node1 * p1 = & n1 ;
  if(p1->hasData()) {
    std::cout<<"Yes p1->hasData()"<<std::endl;
    std::cout<<"data = "<<static_cast< Node2<int> * >( p1)->data<<std::endl; }
  else
    std::cout<<"No p1->hasData()"<<std::endl;
  Node2<int> n2;
  n2.data = 777 ;
  Node1 * p2 = & n2 ;
  if(p2->hasData()){
    std::cout<<"Yes p2->hasData()"<<std::endl;
    std::cout<<"data = "<<static_cast< Node2<int> * >( p2)->data<<std::endl; }
  else
    std::cout<<"No p2->hasData()"<<std::endl;
  sNode1<int> sn1;
  sNode1<int> * psn1 = & sn1;
  if(psn1->son){
    std::cout<<"Yes psn1.son"<<std::endl;
    std::cout<<"data = "<<psn1->son->data<<std::endl;}
  else
    std::cout<<"No psn1.son"<<std::endl;
  sNode2<int> sn2;
  sn2.data = 666 ;
  sNode1<int> * psn2 = & sn2.base;
  if(psn2->son){
    std::cout<<"Yes psn2.son"<<std::endl;
    std::cout<<"data = "<<psn2->son->data<<std::endl;}
  else
    std::cout<<"No psn2.son"<<std::endl;
}

Вывод :

$ g++ -std=c++11 -Wall -Wextra -Wpedantic poli.cpp -o poli && ./poli
No p1->hasData()
Yes p2->hasData()
data = 777
No psn1.son
Yes psn2.son
data = 666
→ Ссылка