Check if an object has a member

Hello,

I am trying to check if a given object has a member. For instance:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <string>
#include <vector>

class Animal{};


class Person: public Animal
{
public:
	std::string name = "Michael Scott";
};


class Bird: public Animal {};

int main() 
{

	auto animal = new Animal;
	auto person = new Person;
	auto bird = new Bird;

	std::vector<Animal*> creatures {animal, person, bird};
	for (auto c: creatures)
	{
		std::cout << c << std::endl;
		/*
		if c has the attribute "name", do what ever
		*/
	}

	return 0;
	
}


In python it would as simple as writing hasAttr(c, "name"), but I have been researching how to do it in C++ and I didn't find a clear answer for this.

Thanks,

R
Hello. Maybe it's not the answer which you expected, but if you want to check if a class has a derived-type object, you can use is_base_of. It could be useful for you instead of searching for a hypothetical member. If the resut is false, you have no member acces to the derived class... Just an idea ++

PS : but in your example, only Person class has acces to the name member :/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <string>
#include <vector>

class Animal {};

class Person : public Animal
{
public:
	std::string name = "Michael Scott";
};

class Bird : public Animal {};

int main()
{
	auto animal = new Animal;
	auto person = new Person;
	auto bird = new Bird;

	std::vector<Animal*> creatures{ animal, person, bird };

	std::cout << std::boolalpha;
	std::cout << std::is_base_of<Animal, Person>::value << "\n"; // true
	std::cout << std::is_base_of<Animal, Bird>::value << "\n";   // true
	std::cout << std::is_base_of<Person, Animal>::value << "\n"; // false
	std::cout << std::is_base_of<Person, Bird>::value << "\n";   // false
	std::cout << std::is_base_of<Bird, Animal>::value << "\n";   // false
	std::cout << std::is_base_of<Bird, Person>::value << "\n";   // false

	return 0;
}
Last edited on
We do know that Person has such member, because we see the:
1
2
3
4
5
class Person: public Animal
{
public:
	std::string name = "Michael Scott";
};


The C++ question is thus: What is the dynamic runtime type of the object pointed to by Animal* ?

A dynamic_cast can help:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <string>
#include <vector>

class Animal
{
public:
    virtual ~Animal() = default;
};

class Person: public Animal
{
public:
	std::string name = "Michael Scott";
};

class Bird: public Animal {};

int main() 
{

	auto animal = new Animal;
	auto person = new Person;
	auto bird = new Bird;

	std::vector<Animal*> creatures {animal, person, bird};
	for (auto c: creatures)
	{
		std::cout << c << std::endl;
		if ( auto p = dynamic_cast<Person*>( c ) )
		{
		    std::cout << p->name << '\n';
		}
	}
    
	for (auto c: creatures) delete c;
}


However, much more common is to have common interface on the base class that the derived classes can embellish:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <string>
#include <vector>

class Animal
{
public:
    virtual std::string name() { return ""; }
};

class Person: public Animal
{
	std::string name_m = "Michael Scott";
public:
    virtual std::string name() { return name_m; }
};

class Bird: public Animal {};

int main() 
{
	auto animal = new Animal;
	auto person = new Person;
	auto bird = new Bird;

	std::vector<Animal*> creatures {animal, person, bird};
	for (auto c: creatures)
	{
		std::cout << c << ' ' << c->name() << '\n';
	}
    
    for (auto c: creatures) delete c;
}
Cool,
thank you both.
So dynamic_casting works because it it fails it returns a Null, interesting.

Cheers,
R
Clever, but confusing :/
In this case, the Class Animal must be re-defined by the derived Class.
So we have to use a virtual function. Right?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <vector>

class Animal
{
public: // required ??? without it code does not compile
    virtual ~Animal() = default;
};

class Person : public virtual Animal
{
public:
    std::string name = "Michael Scott";
};

class Bird : public virtual Animal {};

int main()
{
    auto animal = new Animal;
    auto person = new Person;
    auto bird = new Bird;

    std::vector<Animal*> creatures{ animal, person, bird };

    for (auto c : creatures)
    {
        if (auto p = dynamic_cast<Person*>(c))
        {
            std::cout << p->name << std::endl;
            p->name = "Another name"; // change it for test
            std::cout << p->name << std::endl;
        }
    }
}
Last edited on
So we have to use a virtual function. Right?
dynamic_cast requires that the source of the conversion is polymorphic.
The natural choice is to add a virtual destructor to the base class.

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <string>

struct animal { virtual ~animal() = default; }; 
struct person : animal { std::string name = "unnamed"; };

int main()
{
  animal const& a = person{}; 
  std::cout << "name: " << dynamic_cast<person const&>(a).name << '\n';
}
Last edited on
rudiHammad wrote:
In python it would as simple as writing hasAttr(c, "name"), but I have been researching how to do it in C++ and I didn't find a clear answer for this.

There isn't really anything equivalent because the languages are so different. In C++ we would normally try to solve it some other way.

One way would be to let every Animal have a name that might be empty or null to signal that there is no name. keskiverto have shown one variation of this. If you don't want to use inheritance you could just use a name string member variable, and possibly an enum to signal what type of animal it is.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <string>
#include <vector>

enum class AnimalType
{
	person,
	bird
};

struct Animal
{
	AnimalType type;
	std::string name;
};

class Bird: public Animal {};

int main() 
{
	Animal person{AnimalType::person, "Michael Scott"};
	Animal bird {AnimalType::bird, ""};

	std::vector<Animal*> creatures {&person, &bird};
	for (Animal* c : creatures)
	{
		if (!c->name.empty())
		{
			// do what ever
		}
	}
}
Last edited on
Needing to do specific run-time checks for a class type when using a class is often the sign of a badly designed class structure.

As another take on this, consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <string>
#include <vector>

class Animal {
public:
	Animal() {}

	std::string name() const {
		return name_m;
	}

protected:
	std::string name_m;
	Animal(const std::string& n) : name_m(n) {}
};

class Person : public Animal {
public:
	Person() : Animal("Michael Scott") {}
};

class Bird : public Animal {
public:
	Bird() {}
};

int main() {
	const auto person { new Person };
	const auto bird { new Bird };
	const auto animal { new Animal };

	const std::vector<Animal*> creatures { animal, person, bird };

	for (const auto& c : creatures)
		std::cout << c->name() << '\n';

	for (const auto& c : creatures)
		delete c;
}


Last edited on
Apart from seeplus great comment about design, there is C++ reflection:

https://en.cppreference.com/w/cpp/experimental/reflect

There is a version of clang that implements this, one may have to build it from source though.

https://github.com/compiler-explorer/compiler-explorer/issues/3123

As mentioned there, one can test it on compiler explorer.

There are many other versions that do various levels of reflection.
I doubt reflection is the right answer here. Mainly since this is the beginners section and reflection will be more of an expert tool and it's not even standardized yet. But also because I don't see how you would use it in this situation. I mean, you wouldn't be able to extract information from an Animal* that is only available in one of its derived classes unless you cast the pointer to that type first, would you?

Remember that the reflection that is being proposed for C++ is static (compile-time) reflection, not the "dynamic" (runtime) reflection seen in some other languages.
Last edited on
@Peter87

Yes, I agree :+)
Needing to do specific checks for a class type when using a class is often the sign of a badly designed class structure.


I can't really disagree with this, but, I will say that having things know what they are via an explicit field you throw into them (enum, usually) is often very handy. Maybe its admitting your design isnt perfect to inject such a thing -- its a back door of sorts, really-- but it would certainly solve the OP's ask (if thing.type == e_person cout thing.name). Ive used this a bit when the target was a union, instead of OOP, where it makes more sense.
>Needing to do specific checks for a class type when using a class is often the sign of a badly designed class structure.

Specific checks (at compile-time) for the properties of a type is often required in well designed generic code.
That is the raison d'ĂȘtre for the existence of <type_traits> and standard traits helper types ( std::allocator_traits<>, std::iterator_traits<> etc. ).
And for the interest in adding static reflection facilities to the language.
Last edited on
I was referring to run-time checks - post amended.
Topic archived. No new replies allowed.