When learning C++, the books always create structs as follows:
struct X{
int a;
};
X y;
X *yp; // pointer to object of X class
But I've seen some C++ code online where people instead use the following syntax:
struct X y;
struct X *yp;
Why do they add the struct in front and is there any difference between the two methods of creating objects of X class.
In C++ (as opposed to C) you can mostly just write X when X is a struct type. You still need to write struct X
for disambiguation in some rare cases, and
when X has not yet been declared.
Examples of the last point:
in a friend declaration,
as an id type for a template,
with the usual PIMPL idiom .
Example of the first point:
struct A {};
void A() {}
auto main() -> int
{
void (*f)() = &A;
//A x; // !nyet
struct A x;
}
This is a heritage from C. In C, the following code:
struct Foo
{
int a;
};
created a struct, and put its tag "Foo" in its own 'tag-namespace'
the only way to access it was to do:
struct Foo foo;
Or, more common:
typedef struct Foo Foo;
Foo foo;
However, in C++ the tag is not just placed in a separate tag-namespace, but also
in the enclosing namespace. But for backwards compatibility, it still allows you to
access it using struct Name
There is an additional use of the construct struct Name, both in C and C++
and that is a forward declaration:
struct Later;
Later is here an incomplete type, you can use it only for things that does not
need to know its size (such as creating a pointer)
Related
I am a bit confused when using struct in c/c++. Traditionally, when I use struct, I usually use it as:
typedef struct Name{
int a;
};
Name var;
Although it is considered a bad practice from Linus, it's somehow common.
Yet, I wonder
struct Name{
int a;
};
Name var;
Seems to serve the same purpose, is typedef really necessary?
In fact, shouldn't it be
struct Name{
int a;
};
struct Name var;
Why is the struct from "Name" omitted? If it can always be omitted, does that mean typedef struct is totally useless?
For:
typedef struct Name{
int a;
};
Name var;
The definition should be:
typedef struct Name{
int a;
} Name;
Name var;
Otherwise you are not aliasing the type.
In C++ this doesn't make sense, when you declare struct Name you can already instantiate Name omitting the struct keyword, as you do in the second code snippet, which would not work for C. It behaves similarly to class, in this regard, you don't declare class Name var;, just Name var;.
In C I don't agree it's a bad practice, it's a user defined type, why would you always use struct if you can omit it, any programmer worthy of that name should be able to identify a user defined type, it's not rocket science. This though is opinion based. If it's bad practice we will need to revise the whole notion, not only in C++ but also C#, where class and struct keywords are always omitted when instantiating objects.
As for aliasing pointers, I completely agree, I do not like it one bit, though this can also be seen as opinion based.
So to answer your direct questions:
Seems to serve the same purpose, is typedef really necessary?
For the purpose you describe in C yes, in C++ no.
Why is the struct from "Name" omitted?
In C it cannot be ommited, unless you typedefine it, in C++ not only it can, but it should, it's not needed at all.
If it can always be omitted, does that mean typedef struct is totally useless?
As you can see, it's not useless.
Always using struct keyword while initializing a variable could be lengthy (or whatever you think). That's why there's a typedef keyword (although it have many other uses too).
You can declare a struct with typedef like this:
typedef struct{
int a;
}var;
or
struct Name{
int a;
};
typedef struct Name var;
Then use it like:
var my_age;
However, the above explanation covers only C, whereas in C++ structs are similar to classes but their members are public by default.
So, in C++ you can directly use the struct's name without typing struct keyword again n again
struct Name {
int a;
};
Name my_age;
In C and C++, rules are different. The code you show is clearly C++, it wouldn’t compile in C.
With the following definitions:
struct Foo {
/*fields*/
};
typedef struct Bar {
/*fields*/
} Baz;
in C, variable declarations struct Foo var, struct Bar var, Baz var are valid, but plain Foo var or Bar var are not. In C++ all such variable declarations are valid. Thus, C code would typically look like:
struct Foo {
/*fields*/
};
typedef struct {
/*fields*/
} Baz;
struct Foo var1;
Baz var2;
while in C++, the typical form is:
struct Foo {
/*fields*/
};
Foo var;
UPD: technically, that’s because in struct Foo {..., in C type name is struct Foo; while in C++ the name is simply Foo, and struct is only needed to declare the type, not to use it.
class Impl{
char c[32];
};
typedef struct X{
int u;
int v;
int w;
int x;
}X ;
class A{
public:
int a;
int b;
Impl c;
int d;
};
class B : public A{
public:
union U{
using A::c;
X z;
}ba ;
int bb;
};
The requirement is to remap some bytes of the base class in its client class.
I get error: type ‘A’ is not a base type for type B::U.
I know the alternative solution would be to simply cast A::c as struct X - just thought this kind of solution would look elegant.
You appear to have a fundamental misunderstanding of what types defined within other types are.
In some languages, when you declare a type within another type, instances of that child-type have access to its parent's state. This isn't the case in C++.
union U{
using A::c;
X z;
};
U ba;
this is just another type. You can do this:
int main() {
B::U u;
}
and the u instance isn't embedded within an instance of B (nor A).
What more, X and Impl are unrelated types. "Treating memory as" unions isn't valid C++; it is a hack that a lot of people use, but it isn't actually supported by the C++ standard.
In C++, objects are of one type or another, they cannot be accessed as either except in extremely limited ways, and union doesn't let you treat a struct of ints as a struct containing an array of chars.
Take this:
union bob {
Impl impl;
X x;
};
there is no legal way in C++ to store an X in bob, then access it via the impl member.
You can access the bytes of an X, but you cannot do it through a union. union simply let you have an area of storage that can be either type A or type B. Barring some extremely narrow circumstances involving structure prefixes, you cannot access the data in a union through any means except the exact type that the union currently holds.
Many compilers permit this technique to a greater or lesser extent, but any solution there is going to be compiler specific and not a general C++ solution.
template<class T, class U>
T make_byte_copy( U const& u ) {
static_assert( sizeof(T)<=sizeof(U) );
static_assert( is_trivially_copyable<T>{} );
static_assert( is_trivially_copyable<U>{} );
T t;
std::memcpy( std::addressof(t), std::addressof(u), sizeof(T) );
return t;
}
X getX() const {
return make_byte_copy<X>(c);
}
void setX(X const& in) const {
c = make_byte_copy<impl>(in);
}
this is a rough sketch of how you can read bytes from one type to another. I'd advise asking a SO question on the topic, as I may have errors above, but a technique like the above is going to work.
Another approach involves placement new. You can create an X within the memory of Impl.
This is quite tricky to do without invoking undefined behaviour. There are lots of ways to do it that seem to work but violate the standard.
If you want this approach, it would look roughly like:
struct base {
std::array<char, 24> data;
};
struct bob {int x,y,z;};
struct derived:base {
derived(){
static_assert(sizeof(bob)<=sizeof(data));
static_assert(alignof(bob)<=alignof(data));
::new((void*)&data) bob{1,2,3};
}
~derived(){ x()->~bob(); }
bob& x()&{ return *std::launder(reinterpret_cast<bob*>(&data)); }
bob const& x() const&{ return *std::launder(reinterpret_cast<bob const*>(&data)); }
};
but again, I plausibly made some mistakes. If you want to usr this route ask a narrow question about how to do this right.
In C++ consider the grammar rule:
member-access-expression: LHS member-access-operator RHS
(op is .)
and
LHS=unqualified id-expression e.g. that references an instance variable.
RHS=qualified id-expression (with at least one nested identifier)
example: a.b::c
If that can ever pass the semantic check, what situation would it be ?
The following experiment:
struct B{};
struct A
{
B b;
};
int main()
{
A a;
a.b::c;
}
returns
'b' is not a class, namespace, or enumeration
a.b::c;
^
(demo)
This tends to hint to me that there can't be any legal case of a qualified-id on the right of a member access.
A very simple example is if you want to call a member function of a parent class:
struct A {
void f();
};
struct B: A {
void f();
};
B b;
b.A::f();
One use case is accessing members of an enum within some struct A by using an instance of A (rather than using the enum directly via A::b::c):
struct A {
enum class b { c }; // can be unscoped as well
};
A a;
a.b::c; // Access to enum value c - similarly, A::b::c would work
Here's a trivial example:
struct A {
void f() {}
};
int main()
{
A a;
a.A::f();
}
A::f() is a qualified version of the name for the function f that's a member of A. You can use it in member access just like the "short" (or unqualified) name.
In fact, one might argue that every time you write a.f(), that's a shortcut for a.A::f() (with the A:: part being taken automatically from decltype(a)).
There's nothing magic about this, though it's unusual to see the construct outside of the sort of scenarios the other answerers demonstrated, because in this example it's redundant.
While reading about the visitor pattern I ran into this snippet of code:
virtual void visit(class Composite *, Component*) = 0;
This is a member function, and it seems to be forward declaring the class Composite inside its parameters. I tried this with just a normal function, like so:
void accept(class A a);
for some class A that I haven't declared or defined yet and the code worked fine. Why is this allowed? How, if at all, is it different from forward declaring before the line? Has anything changed recently in the standard in regards to this?
Many people are claiming this is a leftover of C, but then why does this code compile fine in C++, but not C?
#include <stdio.h>
int process(struct A a);
struct A{
int x;
};
int process(struct A a){
return a.x;
}
int main(void)
{
struct A a = {2};
printf("%d", process(a));
return 0;
}
This is called an incomplete type, and is a concept C++ inherited from C.
Incomplete types work this way: before you've defined a class B in your code, you can use class B varname as, say, an argument in function prototypes, or use pointers to this type as class B* ptr - anywhere where no details about a type besides its name are really needed.
Actually, you can write it differently - just put a class B; (which should work as a class declaration) before you use it as an incomplete type, and then you can write B varname instead of class B varname.
Pointers to incomplete types are often used with opaque pointers, which are probably the most common use of incomplete types in C++. Opaque pointers are described well enough in the linked Wikipedia article. Put short, it is a technique that allows your API to hide an entire class implementation.
Using the incomplete type syntaxis you describe in your question, the example code from Wikipedia:
//header file:
class Handle {
public:
/* ... */
private:
struct CheshireCat; // Not defined here
CheshireCat* smile; // Handle
};
//CPP file:
struct Handle::CheshireCat {
int a;
int b;
};
can be rewritten as:
//header file:
class Handle {
public:
/* ... */
private:
struct CheshireCat* smile; // Handle
};
//CPP file:
struct CheshireCat {
int a;
int b;
};
Note this: these code snippets are not equivalent, as the former defines a type Handle::CheshireCat, while the latter has it simply as CheshireCat.
On the code you gave as an example:
In C, the reason it doesn't compile is quite simple: the struct A in the function prototype is a declaration scoped to the function prototype, and thus it is different from the struct A which is declared latter. C and C++ have slightly different rules for this specific case. If you forward-declare the struct like this: struct A; before the function prototype, it will compile in both languages!
Other notable uses of this syntaxis:
This syntaxis has an important place as part of C++'s backward compatibility with C. You see, in C, after defining or forward-declaring a struct like this: struct A {}; or struct A;, the type's actual name would be struct A. To use the name as A, you needed to use a typedef. C++ does the latter automatically, but allows you to use A both as struct A and A. Same goes for class-es union-s, and enum-s.
Actually, some argue this has a semantical importance. Consider a function with the following signature: int asdf(A *paramname). Do you know what A is just by looking at the declaration? Is it a class, struct, enum or a union? People say that a signature like that can be made clearer in such a way: int asdf(enum A *paramname). This is a nice way of writing self-documenting code.
In C, structure names were not accessible without the struct keyword:
struct Foo {};
void bar(struct Foo foo) {...}
You could get around this by using a typedef as well:
typedef struct Foo {} Foo;
void bar(Foo foo) {...}
In C++, this remains for backward compatibility. It's been logically extended, including support for the class keyword instead of struct. class Composite * is almost equivalent to just saying Composite * in this regard. It is not necessarily used as a forward declaration, just accessing the type name.
Note that it can still be used to disambiguate if necessary:
struct Foo {};
void Foo();
int main() {
Foo foo; //error: Foo refers to the function
struct Foo foo; //okay: struct Foo refers to the class
}
Now the same declaration can introduce a type name, like it does in your accept example and possibly does in the visit example. For a function at namespace scope, if the class being declared is not found, it will be declared in the namespace containing the function (see N4140 [basic.scope.pdecl]/7).
This means that the following will not compile due to the struct/union mismatch:
void foo(struct Bar bar);
union Bar;
The above code is roughly equivalent to:
struct Bar;
void foo(Bar bar);
union Bar;
I have structure(A) and it takes another structure(B) as member.
Now i want structure C as member of A instead of B.
Both B and C are of same type
typedef struct
{
int a;
B b;
}A
typedef struct
{
int a;
}B
typedef struct
{
int a;
}C
How can i assign struct C as member instead of B. How to do typecasting
Please help
Without knowing why you want to do this, its hard to recommend a strategy. Here are a few options though.
Option 1: Use Templates. (C++ only)
template <type T>
struct A
{
int a;
T* t;
};
struct Foo
{
int a;
};
struct B : public Foo
{
};
struct C : public Foo
{
};
struct A<Foo> A_foo;
struct B;
struct C;
A_foo.t = &B; //OK! This can now take pointer to any class that extends Foo.
A_foo.t = &C; //OK!
Option 2: Make struct A contain a void* (not recommended, you will lose all type safety). (Both C/C++)
struct A
{
int a;
void* foo; // you can now assign any pointer to foo :-S
};
C and C++ are statically typed languages. You can't do it. If you declare something as apple, it will stay as apple until the end of the times.
Although they appear to be the same type (and are, in this simple case, identical) they are considered to be different types by the compiler. This makes sense for more complex cases or in C++ where the type system is more complex than in pure C.
You generally shouldn't rely on compiler tricks or hackery to do this sort of assignment. Instead, do it properly. Either directly assign fields or, to simplify code, create a helper function along these lines:
void ASetBWithC(A *a, C c) {
assert(a != NULL);
a->b.a = c.a;
}
C++ also has the assignment operator which you could overload to do your work for you (instead of creating a named helper function) but I suspect this is beyond your current comfort level.