This question already has answers here:
Declaring a variable with "class " keyword vs Declaring one without "class" keyword in function signatures
(4 answers)
Closed 8 years ago.
I'm studying code given to me and I see:
AFPSGameMode::AFPSGameMode(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP) { }
I'm specially curious about the use of the class keyword. Is this standard C++ and if so what does it mean?
Thank you.
The class keyword is allowed here, it's just rare to see it placed here since it can either be completely omitted (if this class has been previously declared) or replaced with the forward declaration:
void foo(const class FPostConstructInitializeProperties& p){ ... }
which is equivalent to:
class FPostConstructInitializeProperties; // <-- forward declaration
void foo(const FPostConstructInitializeProperties& p){ ... }
Don't get confused with the weird naming conventions. The snippet you have provided expresses something like this:
class B{
public:
B(){ }
B(const B& b){ };
};
class A{
public:
B my_b;
A(const class B& b) : my_b(b) { } // <-- class keyword in ctor's param decl.
};
that could be used for example like this (but I guess it's clear enough already):
int main() {
B b;
A a(b);
}
As it was old C, if you have struct say,
struct account
{
int field;
..
};
You can use it for creating its variables (objects) like,
account obj;
or,
struct account obj;.
Same is for class, you may use it, or avoid it. But it is usually not used, but permitted.
Related
This question already has an answer here:
Why does having a declaration of a private base class render a type name inaccessible?
(1 answer)
Closed 1 year ago.
I ran into a problem, that I somehow managed to solve, but still would like to understand the language and the reasoning behind it. I have the following system of three classes:
File class_a.hpp
#pragma once
class A
{
public:
A();
};
File class_b.hpp
#pragma once
#include "class_a.hpp"
class B : A
{
public:
B() : A() {}
virtual double do_something(A &with_object) const;
};
File class_c.hpp
#pragma once
#include "class_b.hpp"
class C : B
{
public:
C() : B() {}
double do_something(::A &with_object) const; // but differently than class B
};
Now if I was not to use the fully qualified name for the type A in the C's do_something() method, I'd get the following error still in editor:
type "A::A" (declared at line 27 of "class_a.hpp") is inaccessible C/C++(265)
What could be possible causing any ambiguity in this case? I certainly haven't redefined or used the name A as an identifier. Is there something happening in the background that makes use of the class name?
Also is the override of the do_something() method guaranteed to work this way, or is qualifying the type A in the B's method also required?
Any advice and/or pointers are also greatly appreciated!
Among other things that are inherited, there are injected-class-names. You can think of them as of hidden type aliases: class A has something like using A = A; in it, pointing to itself.
And remember that class inheritance is private by default.
Since B inherits from A privately, C can't access the contents of A, which includes A's injected-class-name.
Also is the override of the do_something() method guaranteed to work this way, or is qualifying the type A in the B's method also required?
Yes, the override in B is valid. Since B inherits from A directly, it can access all its contents, regardless of whether the inheritance is private or not.
Your code is similar to following. I replaced the injected-class-name with an actual type alias, and got the same behavior.
class A
{
public:
using A_type = A;
};
class B : A
{
public:
virtual double do_something(A_type &with_object) const;
};
class C : B
{
public:
double do_something(A_type &with_object) const;
};
This question already has answers here:
Specify a class member function as a friend of another class?
(8 answers)
Closed 3 years ago.
I'm taking a C++ course, and I came across something I can't wrap my head around. I've tried searching for an answer, but I've come up short.
class A {
friend void C::dec(A&);
private:
int field;
};
class C {
public:
void dec(A& a);
};
void C::dec(A& a) { a.field--; } <-- member A::field is inaccessible
I am aware that for this to work, class A should be declared before, but defined after, class C. But I'm struggling to understand why.
So why is the class member A::field inaccessible when class A is defined before class C?
The problem is not the friend declaration, it's just C is unknown where you declare it in A.
So you define C and forward declare A, then just define C as you already did.
class A;
class C {
public:
void dec(A& a);
};
class A {
friend void C::dec(A&);
private:
int field;
};
void C::dec(A& a) { a.field--; }
This question already has answers here:
Why do I have to access template base class members through the this pointer?
(3 answers)
Closed 8 years ago.
Why can't a C++ compiler recognize that g() and b are inherited members of Superclass as seen in this code:
template<typename T> struct Superclass {
protected:
int b;
void g() {}
};
template<typename T> struct Subclass : public Superclass<T> {
void f() {
g(); // compiler error: uncategorized
b = 3; // compiler error: unrecognized
}
};
If I simplify Subclass and just inherit from Subclass<int> then it compiles. It also compiles when fully qualifying g() as Superclass<T>::g() and Superclass<T>::b. I'm using LLVM GCC 4.2.
Note: If I make g() and b public in the superclass it still fails with same error.
This can be amended by pulling the names into the current scope using using:
template<typename T> struct Subclass : public Superclass<T> {
using Superclass<T>::b;
using Superclass<T>::g;
void f() {
g();
b = 3;
}
};
Or by qualifying the name via the this pointer access:
template<typename T> struct Subclass : public Superclass<T> {
void f() {
this->g();
this->b = 3;
}
};
Or, as you’ve already noticed, by qualifying the full name.
The reason why this is necessary is that C++ doesn’t consider superclass templates for name resolution (because then they are dependent names and dependent names are not considered). It works when you use Superclass<int> because that’s not a template (it’s an instantiation of a template) and thus its nested names are not dependent names.
Konrad's answer doesn't ask or answer the final "why" in all of this. It's not just the C++ committee arbitrarily saying "hey, give up on dependent names, nobody likes them anyway". Rather, the compiler does some checking of the templates even before they're instantiated, and it can't make any sense of g() or b until it knows T, as it can't - in general - select between possible specialisations of the base class (e.g. SuperClass<X> may have int b while SuperClass<Y> has void b() and SuperClass<Z> doesn't have b at all). The more explicit forms are just saying "trust me - this must come from the base class at instantiation time (otherwise there'll be a compiler error then)".
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++: rationale behind hiding rule
Suppose I have a code:
class A
{
public:
void f(int s) {}
};
class B:public A
{
public:
void f() {}
};
int main()
{ B ob;
ob.f(4);
}
Then in this case compiler generates an error that "no matching function for call to ‘B::f(int)'"
But class B has inherited A as public so B must have the function "void f(int s)". Dont know why compiler is generating error here?
That is because B defines a different f, which hides the f inherited from A. If you want both available in B (which is likely), you must bring it into scope with a using-declaration:
class B : public A
{
void f() {}
using A::f;
};
This behaviour is specified in [class.member.loopkup], especially paragrah 4.
When you declare void f() in B, this hides the void f(int) inherited from A. You can bring it back into scope with using:
class B: public A
{
public:
void f() {}
using A::f;
};
This is called Hiding - you can check the C++ FAQ Entry. It describes the problem and the solution.
This question already has answers here:
Why do I have to access template base class members through the this pointer?
(3 answers)
Closed 8 years ago.
Why can't a C++ compiler recognize that g() and b are inherited members of Superclass as seen in this code:
template<typename T> struct Superclass {
protected:
int b;
void g() {}
};
template<typename T> struct Subclass : public Superclass<T> {
void f() {
g(); // compiler error: uncategorized
b = 3; // compiler error: unrecognized
}
};
If I simplify Subclass and just inherit from Subclass<int> then it compiles. It also compiles when fully qualifying g() as Superclass<T>::g() and Superclass<T>::b. I'm using LLVM GCC 4.2.
Note: If I make g() and b public in the superclass it still fails with same error.
This can be amended by pulling the names into the current scope using using:
template<typename T> struct Subclass : public Superclass<T> {
using Superclass<T>::b;
using Superclass<T>::g;
void f() {
g();
b = 3;
}
};
Or by qualifying the name via the this pointer access:
template<typename T> struct Subclass : public Superclass<T> {
void f() {
this->g();
this->b = 3;
}
};
Or, as you’ve already noticed, by qualifying the full name.
The reason why this is necessary is that C++ doesn’t consider superclass templates for name resolution (because then they are dependent names and dependent names are not considered). It works when you use Superclass<int> because that’s not a template (it’s an instantiation of a template) and thus its nested names are not dependent names.
Konrad's answer doesn't ask or answer the final "why" in all of this. It's not just the C++ committee arbitrarily saying "hey, give up on dependent names, nobody likes them anyway". Rather, the compiler does some checking of the templates even before they're instantiated, and it can't make any sense of g() or b until it knows T, as it can't - in general - select between possible specialisations of the base class (e.g. SuperClass<X> may have int b while SuperClass<Y> has void b() and SuperClass<Z> doesn't have b at all). The more explicit forms are just saying "trust me - this must come from the base class at instantiation time (otherwise there'll be a compiler error then)".