Явная нарезка производного объекта

У меня есть некоторая структура классов для проекта, который я строю для своей компании. В какой-то момент я увидел, что «обычно нежелательные» фрагменты производного объекта могут фактически сделать мой код эффективным. Пожалуйста, обратите внимание:

class Base {
private:
int myType; //some constant here
public:
Base(): myType(1)
{
if(someTest())
{
myTest = 0; // signifies that this object is not working well for me
}  // if the test succeeds, now I know this is a TYPE1 object
}

virtual bool someTest() { /* does make some validation tests */ }
int GetMyType() { return myType; }

// some more virtual functions follow
}

class Derived: public Base {
public:
Derived() : Base()
{
if( someTest() /*calls the derived*/ )
{
myType =2; // signifies that this is a TYPE2 object
/* Do something more*/
}
}

virtual bool someTest() { /* does make OTHER validation tests */ }
}

Теперь, если someTest () в Derived завершается с ошибкой, это показывает, что мой объект на самом деле имеет базовый тип (myType = 1) или неисправный объект (myType = 0). Так как эти вещи находятся в конструкторах, и так как я не могу использовать обработку исключений (встроенная система); Я думал об этом:

{
// this is the object holder test block
// there is some latch - Base* - above = let's call it "ObjectHolder"extern Base* ObjectHolder;Derived * deriv = new Derived();
int dType = deriv->GetMyType() ;
if( dType == 1) // if test at base succeded but the one in derived failed
Base = & static_cast<Base> (*deriv); // specifically slice the object
else if(dType =2)
Base = deriv;
else
delete deriv; // this is a TYPE0 - nonworking- object so don't latch it

// use other implemented methods to do work ...

}

Теперь, почему я получил такой дизайн? Ну, пока я проектировал классы, так как методы внутренней работы классов «Base» (тип 1) и «Derived» (тип 2) различаются (и есть возможность типа 3,4,5 …. объекты, которые также различаются внутри), и так как я не хотел делать и проверять «if-then-else» в каждом отдельном методе; Я думал, что сделаю такой дизайн и сделаю разные методы виртуальными, чтобы их можно было правильно вызывать (благодаря полиморфизму), в то время как общие методы могут быть в некотором базовом классе.

Но сейчас, во-первых, я не уверен, что этот странный синтаксис ( & static_cast < База> * производная) является правильной (проверено и, похоже, работает, но я просто хочу убедиться, что это не из-за удачи); и во-вторых, я не уверен, что это «предложенный метод» для достижения этой цели — я подозреваю, что этот синтаксис может вызвать утечки памяти или что-то …

Немного изменил код (также исправил синтаксис), чтобы прояснить проблему.

Теперь, так как &(static_cast (* производная)) является ошибочным подходом, я подумал, смогу ли я создать «конструктор копирования», который обходит проверку в базовом классе (что на самом деле является причиной того, что я пробую эти вещи — я не хочу этот тест быть запущенным в некоторых случаях). Как ниже:

class Base {
// other stuff is like above

// cc:
Base(const Base &other) : myType(other.myType)
{
// no test is performed here!
}

// like other one above
}

С этим написано, я думаю, что я могу сделать это сейчас в тестовом блоке:

{
// the code above

if( dType == 1) // if test at base succeded but the one in derived failed
Base = new Base(*deriv); // specifically slice the object with cc

// code goes on ...
}

Как насчет этого?

0

Решение

Конечно, если вы хотите создать два типа объектов, правильный способ — иметь фабричную функцию, которая содержит «if (sometest)», а затем создает правильный тип объекта:

 Base* factory(...)
{
if(sometest())
{
return new Derived;
}
else
{
return new Base;
}
}

Таким образом, вы не будете без необходимости создавать производный тип объекта, когда вам действительно нужен объект базового типа. Имейте также в виду, что если вы нарезаете объект, ваш vtable
связанные с производными объектами, которые были нарезаны, по-прежнему будут производными vtable,

Изменить: Вот некоторый код, чтобы показать проблему с нарезкой:

#include <iostream>

using namespace std;

class Base
{
public:
virtual void func() { cout << "Base" << endl; }
};class Derived : public Base
{
public:
virtual void func() { cout << "Derived" << endl; }
};int main()
{
Base *list[10];
for(int i = 0; i < 10; i++)
{
if (i % 2)
{
list[i] = new Base;
}
else
{
list[i] = new Derived;
}
}

list[2] = &*(static_cast<Base*>(list[2]));

for(int i = 0; i < 10; i++)
{
list[i]->func();
}
return 0;
}

Выход:

Derived
Base
Derived     <- should have changed to "Base" if questio was "right".
Base
Derived
Base
Derived
Base
Derived
Base

Используя синтаксис для «нарезки», как указано в исходном вопросе:
&(static_cast<Base>(*list[2])); (согласно адаптированному к коду, опубликованному здесь), дает ошибку в обоих clang++ а также g++ компилятор. Суть сообщения та же. Это вариант Clang:

error: taking the address of a temporary object of type 'Base'
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]