это работает
df['cateogry'] = df.apply(lambda x: 'Certain' if sum(x.values >= 1) >= 5 else 'Probable' if sum(x.values >= 1) >= 4 else 'Possible' , axis=1)
Выход
col1 col2 col3 col4 col5 cateogry
0 1 1 1 4 1 Certain
1 0 1 1 1 1 Probable
2 0 0 1 1 1 Possible
Я думаю, что вы ищете то, что называется "идиома pimpl". Чтобы понять, как это работает, вам нужно понять, что в C ++ вы можете объявить что-то вроде пересылки следующим образом.
class CWidget; // Widget will exist sometime in the future
CWidget* aWidget; // An address (integer) to something that
// isn't defined *yet*
// later on define CWidget to be something concrete
class CWidget
{
// methods and such
};
Таким образом, пересылка объявлений означает обещание полностью объявить тип позже. Оно говорит: «Будет такая вещь, которая называется CWidget, я обещаю. Я расскажу вам больше об этом позже».
Правила прямого объявления говорят, что вы можете определить указатель или ссылку на что-то, что было форвард объявлен. Это связано с тем, что указатели и ссылки на самом деле являются просто адресами - числом, где будет определена эта еще не определенная вещь. Возможность объявить указатель на что-либо без полного объявления этого удобна по многим причинам.
Это полезно здесь, потому что вы можете использовать это, чтобы скрыть некоторые внутренние элементы класса, используя метод "pimpl". Pimpl означает «указатель на реализацию». Таким образом, вместо «виджета» у вас есть класс, который является реальной реализацией. Класс, который вы объявляете в своем заголовке, является просто переходом к классу CImpl. Вот как это работает:
// Thing.h
class CThing
{
public:
// CThings methods and constructors...
CThing();
void DoSomething();
int GetSomething();
~CThing();
private:
// CThing store's a pointer to some implementation class to
// be defined later
class CImpl; // forward declaration to CImpl
CImpl* m_pimpl; // pointer to my implementation
};
Thing.cpp имеет методы CThing, определенные как переходы к impl:
// Fully define Impl
class CThing::CImpl
{
private:
// all variables
public:
// methods inlined
CImpl()
{
// constructor
}
void DoSomething()
{
// actual code that does something
}
//etc for all methods
};
// CThing methods are just pass-throughs
CThing::CThing() : m_pimpl(new CThing::CImpl());
{
}
CThing::~CThing()
{
delete m_pimpl;
}
int CThing::GetSomething()
{
return m_pimpl->GetSomething();
}
void CThing::DoSomething()
{
m_impl->DoSomething();
}
tada! Вы спрятали все детали в вашем cpp, а ваш заголовочный файл представляет собой очень аккуратный список методов. Это отличная вещь. Единственное, что вы можете увидеть отличным от шаблона выше, это то, что люди могут использовать boost :: shared_ptr <> или другой умный указатель для impl. Что-то, что удаляет себя.
Также имейте в виду, что этот метод приносит некоторые неудобства. Отладка может быть немного раздражает (дополнительный уровень перенаправления, чтобы пройти через). Это также много накладных расходов на создание класса. Если вы сделаете это для каждого класса, вы устанете от всего набора текста :).
The pimpl idiom adds a void* private data member to your class, and this is a useful technique if you need something quick & dirty. It has its drawbacks however. Main among those is it makes it difficult to use polymorphism on the abstract type. Sometimes you might want an abstract base class and subclasses of that base class, collect pointers to all the different types in a vector and call methods on them. In addition, if the purpose of the pimpl idiom is to hide the implementation details of the class then it only almost succeeds: the pointer itself is an implementation detail. An opaque implementation detail, perhaps. But an implementation detail nonetheless.
An alternative to the pimpl idiom exists which can be used to remove all of the implementation details from the interface while providing a base type that can be used polymorphically, if needed.
In your DLL's header file (the one #included by client code) create an abstract class with only public methods and concepts which dictate how the class is to be instantiated (eg, public factory methods & clone methods):
kennel.h
/****************************************************************
***
*** The declaration of the kennel namespace & its members
*** would typically be in a header file.
***/
// Provide an abstract interface class which clients will have pointers to.
// Do not permit client code to instantiate this class directly.
namespace kennel
{
class Animal
{
public:
// factory method
static Animal* createDog(); // factory method
static Animal* createCat(); // factory method
virtual Animal* clone() const = 0; // creates a duplicate object
virtual string speak() const = 0; // says something this animal might say
virtual unsigned long serialNumber() const = 0; // returns a bit of state data
virtual string name() const = 0; // retuyrns this animal's name
virtual string type() const = 0; // returns the type of animal this is
virtual ~Animal() {}; // ensures the correct subclass' dtor is called when deleteing an Animal*
};
};
...Animal is an abstract base class and so cannot be instantiated; no private ctor needs to be declared. The presence of the virtual dtor ensures that if someone delete
s an Animal*
, the proper subclass' dtor will also be called.
In order to implement different subclasses of the base type (eg dogs & cats), you would declare implementation-level classes in your DLL. These classes derive ultimately from the abstract base class you declared in your header file, and the factory methods would actually instantiate one of these subclasses.
dll.cpp:
/****************************************************************
***
*** The code that follows implements the interface
*** declared above, and would typically be in a cc
*** file.
***/
// Implementation of the Animal abstract interface
// this implementation includes several features
// found in real code:
// Each animal type has it's own properties/behavior (speak)
// Each instance has it's own member data (name)
// All Animals share some common properties/data (serial number)
//
namespace
{
// AnimalImpl provides properties & data that are shared by
// all Animals (serial number, clone)
class AnimalImpl : public kennel::Animal
{
public:
unsigned long serialNumber() const;
string type() const;
protected:
AnimalImpl();
AnimalImpl(const AnimalImpl& rhs);
virtual ~AnimalImpl();
private:
unsigned long serial_; // each Animal has its own serial number
static unsigned long lastSerial_; // this increments every time an AnimalImpl is created
};
class Dog : public AnimalImpl
{
public:
kennel::Animal* clone() const { Dog* copy = new Dog(*this); return copy;}
std::string speak() const { return "Woof!"; }
std::string name() const { return name_; }
Dog(const char* name) : name_(name) {};
virtual ~Dog() { cout << type() << " #" << serialNumber() << " is napping..." << endl; }
protected:
Dog(const Dog& rhs) : AnimalImpl(rhs), name_(rhs.name_) {};
private:
std::string name_;
};
class Cat : public AnimalImpl
{
public:
kennel::Animal* clone() const { Cat* copy = new Cat(*this); return copy;}
std::string speak() const { return "Meow!"; }
std::string name() const { return name_; }
Cat(const char* name) : name_(name) {};
virtual ~Cat() { cout << type() << " #" << serialNumber() << " escaped!" << endl; }
protected:
Cat(const Cat& rhs) : AnimalImpl(rhs), name_(rhs.name_) {};
private:
std::string name_;
};
};
unsigned long AnimalImpl::lastSerial_ = 0;
// Implementation of interface-level functions
// In this case, just the factory functions.
kennel::Animal* kennel::Animal::createDog()
{
static const char* name [] = {"Kita", "Duffy", "Fido", "Bowser", "Spot", "Snoopy", "Smkoky"};
static const size_t numNames = sizeof(name)/sizeof(name[0]);
size_t ix = rand()/(RAND_MAX/numNames);
Dog* ret = new Dog(name[ix]);
return ret;
}
kennel::Animal* kennel::Animal::createCat()
{
static const char* name [] = {"Murpyhy", "Jasmine", "Spike", "Heathcliff", "Jerry", "Garfield"};
static const size_t numNames = sizeof(name)/sizeof(name[0]);
size_t ix = rand()/(RAND_MAX/numNames);
Cat* ret = new Cat(name[ix]);
return ret;
}
// Implementation of base implementation class
AnimalImpl::AnimalImpl()
: serial_(++lastSerial_)
{
};
AnimalImpl::AnimalImpl(const AnimalImpl& rhs)
: serial_(rhs.serial_)
{
};
AnimalImpl::~AnimalImpl()
{
};
unsigned long AnimalImpl::serialNumber() const
{
return serial_;
}
string AnimalImpl::type() const
{
if( dynamic_cast<const Dog*>(this) )
return "Dog";
if( dynamic_cast<const Cat*>(this) )
return "Cat";
else
return "Alien";
}
Now you have the interface defined in the header & the implementation details completely seperated out where client code can't see it at all. You would use this by calling methods declared in your header file from code that links to your DLL. Here's a sample driver:
main.cpp:
std::string dump(const kennel::Animal* animal)
{
stringstream ss;
ss << animal->type() << " #" << animal->serialNumber() << " says '" << animal->speak() << "'" << endl;
return ss.str();
}
template<class T> void del_ptr(T* p)
{
delete p;
}
int main()
{
srand((unsigned) time(0));
// start up a new farm
typedef vector<kennel::Animal*> Animals;
Animals farm;
// add 20 animals to the farm
for( size_t n = 0; n < 20; ++n )
{
bool makeDog = rand()/(RAND_MAX/2) != 0;
if( makeDog )
farm.push_back(kennel::Animal::createDog());
else
farm.push_back(kennel::Animal::createCat());
}
// list all the animals in the farm to the console
transform(farm.begin(), farm.end(), ostream_iterator<string>(cout, ""), dump);
// deallocate all the animals in the farm
for_each( farm.begin(), farm.end(), del_ptr<kennel::Animal>);
return 0;
}
Yes, this can be a desireable thing to do. One easy way is to make the implementation class derive from the class defined in the header.
The downside is that the compiler won't know how to construct your class, so you'll need some kind of factory method to get instances of the class. It will be impossible to have local instances on the stack.
Вы должны объявить все члены в заголовке, чтобы компилятор знал, насколько велик объект, и так далее.
Но вы можете решить эту проблему с помощью интерфейса:
ext.h:
class ExtClass
{
public:
virtual void func1(int xy) = 0;
virtual int func2(XYClass ¶m) = 0;
};
int.h:
class ExtClassImpl : public ExtClass
{
public:
void func1(int xy);
int func2(XYClass¶m);
};
int.cpp:
void ExtClassImpl::func1(int xy)
{
...
}
int ExtClassImpl::func2(XYClass¶m)
{
...
}
Is it possible to make a C++ header file (.h) that declares a class, and its public methods, but does not declare the private members in that class?
Самый близкий ответ - идиома PIMPL.
См. это Идиома быстрого Pimpl от Herb Sutter.
IMO Pimpl действительно полезен на начальных этапах разработки, где ваш заголовочный файл буду менять много раз. Pimpl имеет свою стоимость из-за размещения \ освобождения внутреннего объекта в куче.