Commit cbb40945 by Nathan Sidwell Committed by Nathan Sidwell

cp-tree.h (IDENTIFIER_VIRTUAL_P): Document.

cp:
	* cp-tree.h (IDENTIFIER_VIRTUAL_P): Document.
	(get_matching_virtual): Remove.
	(look_for_overrides): Declare new function.
	* decl.c (grokfndecl): Don't set IDENTIFIER_VIRTUAL_P or
	DECL_VINDEX here.
	* class.c (check_for_override): Move base class iteration code
	to look_for_overrides.
	* search.c (next_baselink): Remove.
	(get_virtuals_named_this): Remove.
	(get_virtual_destructor): Remove.
	(tree_has_any_destructors_p): Remove.
	(struct gvnt_info): Remove.
	(check_final_overrider): Remove `virtual' from error messages.
	(get_matching_virtuals): Remove. Move functionality to ...
	(look_for_overrides): ... here, and ...
	(look_for_overrides_r): ... here. Set DECL_VIRTUAL_P, if found
	to be overriding.
testsuite:
	* g++.old-deja/g++.h/spec6.C: Remove some of the XFAILS.
	* g++.old-deja/g++.other/virtual10.C: New test.

From-SVN: r38040
parent 61402b80
2000-12-05 Nathan Sidwell <nathan@codesourcery.com> 2000-12-05 Nathan Sidwell <nathan@codesourcery.com>
* cp-tree.h (IDENTIFIER_VIRTUAL_P): Document.
(get_matching_virtual): Remove.
(look_for_overrides): Declare new function.
* decl.c (grokfndecl): Don't set IDENTIFIER_VIRTUAL_P or
DECL_VINDEX here.
* class.c (check_for_override): Move base class iteration code
to look_for_overrides.
* search.c (next_baselink): Remove.
(get_virtuals_named_this): Remove.
(get_virtual_destructor): Remove.
(tree_has_any_destructors_p): Remove.
(struct gvnt_info): Remove.
(check_final_overrider): Remove `virtual' from error messages.
(get_matching_virtuals): Remove. Move functionality to ...
(look_for_overrides): ... here, and ...
(look_for_overrides_r): ... here. Set DECL_VIRTUAL_P, if found
to be overriding.
2000-12-05 Nathan Sidwell <nathan@codesourcery.com>
* typeck.c (get_delta_difference): If via a virtual base, * typeck.c (get_delta_difference): If via a virtual base,
return zero. return zero.
* cvt.c (cp_convert_to_pointer): If via a virtual base, do no * cvt.c (cp_convert_to_pointer): If via a virtual base, do no
......
...@@ -2910,56 +2910,24 @@ static void ...@@ -2910,56 +2910,24 @@ static void
check_for_override (decl, ctype) check_for_override (decl, ctype)
tree decl, ctype; tree decl, ctype;
{ {
tree binfos = BINFO_BASETYPES (TYPE_BINFO (ctype)); if (TREE_CODE (decl) == TEMPLATE_DECL)
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; /* In [temp.mem] we have:
int virtualp = DECL_VIRTUAL_P (decl);
int found_overriden_fn = 0;
for (i = 0; i < n_baselinks; i++) A specialization of a member function template does not
{ override a virtual function from a base class. */
tree base_binfo = TREE_VEC_ELT (binfos, i); return;
if (TYPE_POLYMORPHIC_P (BINFO_TYPE (base_binfo))) if ((DECL_DESTRUCTOR_P (decl)
{ || IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)))
tree tmp = get_matching_virtual && look_for_overrides (ctype, decl)
(base_binfo, decl, DECL_DESTRUCTOR_P (decl)); && !DECL_STATIC_FUNCTION_P (decl))
{
if (tmp && !found_overriden_fn) /* Set DECL_VINDEX to a value that is neither an
{ INTEGER_CST nor the error_mark_node so that
/* If this function overrides some virtual in some base add_virtual_function will realize this is an
class, then the function itself is also necessarily overriding function. */
virtual, even if the user didn't explicitly say so. */ DECL_VINDEX (decl) = decl;
DECL_VIRTUAL_P (decl) = 1; }
if (DECL_VIRTUAL_P (decl))
/* The TMP we really want is the one from the deepest
baseclass on this path, taking care not to
duplicate if we have already found it (via another
path to its virtual baseclass. */
if (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE)
{
cp_error_at ("`static %#D' cannot be declared", decl);
cp_error_at (" since `virtual %#D' declared in base class",
tmp);
break;
}
virtualp = 1;
/* Set DECL_VINDEX to a value that is neither an
INTEGER_CST nor the error_mark_node so that
add_virtual_function will realize this is an
overridden function. */
DECL_VINDEX (decl)
= tree_cons (tmp, NULL_TREE, DECL_VINDEX (decl));
/* We now know that DECL overrides something,
which is all that is important. But, we must
continue to iterate through all the base-classes
in order to allow get_matching_virtual to check for
various illegal overrides. */
found_overriden_fn = 1;
}
}
}
if (virtualp)
{ {
if (DECL_VINDEX (decl) == NULL_TREE) if (DECL_VINDEX (decl) == NULL_TREE)
DECL_VINDEX (decl) = error_mark_node; DECL_VINDEX (decl) = error_mark_node;
......
...@@ -514,7 +514,8 @@ struct tree_srcloc ...@@ -514,7 +514,8 @@ struct tree_srcloc
#define SET_IDENTIFIER_ERROR_LOCUS(NODE,VALUE) \ #define SET_IDENTIFIER_ERROR_LOCUS(NODE,VALUE) \
SET_LANG_ID(NODE, VALUE, error_locus) SET_LANG_ID(NODE, VALUE, error_locus)
/* Nonzero if this identifier is used as a virtual function name somewhere
(optimizes searches). */
#define IDENTIFIER_VIRTUAL_P(NODE) TREE_LANG_FLAG_1(NODE) #define IDENTIFIER_VIRTUAL_P(NODE) TREE_LANG_FLAG_1(NODE)
/* Nonzero if this identifier is the prefix for a mangled C++ operator /* Nonzero if this identifier is the prefix for a mangled C++ operator
...@@ -4250,7 +4251,7 @@ extern tree lookup_field PARAMS ((tree, tree, int, int)); ...@@ -4250,7 +4251,7 @@ extern tree lookup_field PARAMS ((tree, tree, int, int));
extern int lookup_fnfields_1 PARAMS ((tree, tree)); extern int lookup_fnfields_1 PARAMS ((tree, tree));
extern tree lookup_fnfields PARAMS ((tree, tree, int)); extern tree lookup_fnfields PARAMS ((tree, tree, int));
extern tree lookup_member PARAMS ((tree, tree, int, int)); extern tree lookup_member PARAMS ((tree, tree, int, int));
extern tree get_matching_virtual PARAMS ((tree, tree, int)); extern int look_for_overrides PARAMS ((tree, tree));
extern void get_pure_virtuals PARAMS ((tree)); extern void get_pure_virtuals PARAMS ((tree));
extern tree init_vbase_pointers PARAMS ((tree, tree)); extern tree init_vbase_pointers PARAMS ((tree, tree));
extern void get_vbase_types PARAMS ((tree)); extern void get_vbase_types PARAMS ((tree));
......
...@@ -9038,12 +9038,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals, ...@@ -9038,12 +9038,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
return decl; return decl;
if (virtualp) if (virtualp)
{ DECL_VIRTUAL_P (decl) = 1;
DECL_VIRTUAL_P (decl) = 1;
if (DECL_VINDEX (decl) == NULL_TREE)
DECL_VINDEX (decl) = error_mark_node;
IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1;
}
return decl; return decl;
} }
......
...@@ -83,7 +83,6 @@ struct vbase_info ...@@ -83,7 +83,6 @@ struct vbase_info
tree inits; tree inits;
}; };
static tree next_baselink PARAMS ((tree));
static tree get_vbase_1 PARAMS ((tree, tree, unsigned int *)); static tree get_vbase_1 PARAMS ((tree, tree, unsigned int *));
static tree lookup_field_1 PARAMS ((tree, tree)); static tree lookup_field_1 PARAMS ((tree, tree));
static int lookup_fnfields_here PARAMS ((tree, tree)); static int lookup_fnfields_here PARAMS ((tree, tree));
...@@ -110,11 +109,9 @@ static tree dfs_push_type_decls PARAMS ((tree, void *)); ...@@ -110,11 +109,9 @@ static tree dfs_push_type_decls PARAMS ((tree, void *));
static tree dfs_push_decls PARAMS ((tree, void *)); static tree dfs_push_decls PARAMS ((tree, void *));
static tree dfs_unuse_fields PARAMS ((tree, void *)); static tree dfs_unuse_fields PARAMS ((tree, void *));
static tree add_conversions PARAMS ((tree, void *)); static tree add_conversions PARAMS ((tree, void *));
static tree get_virtuals_named_this PARAMS ((tree, tree));
static tree get_virtual_destructor PARAMS ((tree, void *));
static tree tree_has_any_destructor_p PARAMS ((tree, void *));
static int covariant_return_p PARAMS ((tree, tree)); static int covariant_return_p PARAMS ((tree, tree));
static int check_final_overrider PARAMS ((tree, tree)); static int check_final_overrider PARAMS ((tree, tree));
static int look_for_overrides_r PARAMS ((tree, tree));
static struct search_level *push_search_level static struct search_level *push_search_level
PARAMS ((struct stack_level *, struct obstack *)); PARAMS ((struct stack_level *, struct obstack *));
static struct search_level *pop_search_level static struct search_level *pop_search_level
...@@ -124,7 +121,6 @@ static tree bfs_walk ...@@ -124,7 +121,6 @@ static tree bfs_walk
void *)); void *));
static tree lookup_field_queue_p PARAMS ((tree, void *)); static tree lookup_field_queue_p PARAMS ((tree, void *));
static tree lookup_field_r PARAMS ((tree, void *)); static tree lookup_field_r PARAMS ((tree, void *));
static tree get_virtuals_named_this_r PARAMS ((tree, void *));
static tree context_for_name_lookup PARAMS ((tree)); static tree context_for_name_lookup PARAMS ((tree));
static tree canonical_binfo PARAMS ((tree)); static tree canonical_binfo PARAMS ((tree));
static tree shared_marked_p PARAMS ((tree, void *)); static tree shared_marked_p PARAMS ((tree, void *));
...@@ -1867,87 +1863,6 @@ dfs_walk (binfo, fn, qfn, data) ...@@ -1867,87 +1863,6 @@ dfs_walk (binfo, fn, qfn, data)
return dfs_walk_real (binfo, 0, fn, qfn, data); return dfs_walk_real (binfo, 0, fn, qfn, data);
} }
struct gvnt_info
{
/* The name of the function we are looking for. */
tree name;
/* The overloaded functions we have found. */
tree fields;
};
/* Called from get_virtuals_named_this via bfs_walk. */
static tree
get_virtuals_named_this_r (binfo, data)
tree binfo;
void *data;
{
struct gvnt_info *gvnti = (struct gvnt_info *) data;
tree type = BINFO_TYPE (binfo);
int idx;
idx = lookup_fnfields_here (BINFO_TYPE (binfo), gvnti->name);
if (idx >= 0)
gvnti->fields
= tree_cons (binfo,
TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx),
gvnti->fields);
return NULL_TREE;
}
/* Return the virtual functions with the indicated NAME in the type
indicated by BINFO. The result is a TREE_LIST whose TREE_PURPOSE
indicates the base class from which the TREE_VALUE (an OVERLOAD or
just a FUNCTION_DECL) originated. */
static tree
get_virtuals_named_this (binfo, name)
tree binfo;
tree name;
{
struct gvnt_info gvnti;
tree fields;
gvnti.name = name;
gvnti.fields = NULL_TREE;
bfs_walk (binfo, get_virtuals_named_this_r, 0, &gvnti);
/* Get to the function decls, and return the first virtual function
with this name, if there is one. */
for (fields = gvnti.fields; fields; fields = next_baselink (fields))
{
tree fndecl;
for (fndecl = TREE_VALUE (fields); fndecl; fndecl = OVL_NEXT (fndecl))
if (DECL_VINDEX (OVL_CURRENT (fndecl)))
return fields;
}
return NULL_TREE;
}
static tree
get_virtual_destructor (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
tree type = BINFO_TYPE (binfo);
if (TYPE_HAS_DESTRUCTOR (type)
&& DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 1)))
return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 1);
return 0;
}
static tree
tree_has_any_destructor_p (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
tree type = BINFO_TYPE (binfo);
return TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) ? binfo : NULL_TREE;
}
/* Returns > 0 if a function with type DRETTYPE overriding a function /* Returns > 0 if a function with type DRETTYPE overriding a function
with type BRETTYPE is covariant, as defined in [class.virtual]. with type BRETTYPE is covariant, as defined in [class.virtual].
...@@ -2026,124 +1941,128 @@ check_final_overrider (overrider, basefn) ...@@ -2026,124 +1941,128 @@ check_final_overrider (overrider, basefn)
if (pedantic && i == -1) if (pedantic && i == -1)
{ {
cp_pedwarn_at ("invalid covariant return type for `virtual %#D'", overrider); cp_pedwarn_at ("invalid covariant return type for `%#D'", overrider);
cp_pedwarn_at (" overriding `virtual %#D' (must be pointer or reference to class)", basefn); cp_pedwarn_at (" overriding `%#D' (must be pointer or reference to class)", basefn);
} }
} }
else if (IS_AGGR_TYPE_2 (base_return, over_return) else if (IS_AGGR_TYPE_2 (base_return, over_return)
&& same_or_base_type_p (base_return, over_return)) && same_or_base_type_p (base_return, over_return))
{ {
cp_error_at ("invalid covariant return type for `virtual %#D'", overrider); cp_error_at ("invalid covariant return type for `%#D'", overrider);
cp_error_at (" overriding `virtual %#D' (must use pointer or reference)", basefn); cp_error_at (" overriding `%#D' (must use pointer or reference)", basefn);
return 0; return 0;
} }
else if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider)) == NULL_TREE) else if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider)) == NULL_TREE)
{ {
cp_error_at ("conflicting return type specified for `virtual %#D'", overrider); cp_error_at ("conflicting return type specified for `%#D'", overrider);
cp_error_at (" overriding `virtual %#D'", basefn); cp_error_at (" overriding `%#D'", basefn);
SET_IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider), SET_IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider),
DECL_CONTEXT (overrider)); DECL_CONTEXT (overrider));
return 0; return 0;
} }
/* Check throw specifier is subset. */ /* Check throw specifier is subset. */
/* XXX At the moment, punt on an overriding artificial function. We /* XXX At the moment, punt with artificial functions. We
don't generate its exception specifier, so can't check it properly. */ don't generate their exception specifiers, so can't check properly. */
if (! DECL_ARTIFICIAL (overrider) if (! DECL_ARTIFICIAL (overrider)
&& !comp_except_specs (base_throw, over_throw, 0)) && !comp_except_specs (base_throw, over_throw, 0))
{ {
cp_error_at ("looser throw specifier for `virtual %#F'", overrider); cp_error_at ("looser throw specifier for `%#F'", overrider);
cp_error_at (" overriding `virtual %#F'", basefn); cp_error_at (" overriding `%#F'", basefn);
return 0; return 0;
} }
return 1; return 1;
} }
/* Given a class type TYPE, and a function decl FNDECL, look for a /* Given a class TYPE, and a function decl FNDECL, look for
virtual function in TYPE's hierarchy which FNDECL could match as a virtual functions in TYPE's hierarchy which FNDECL overrides.
virtual function. It doesn't matter which one we find. We do not look in TYPE itself, only its bases.
DTORP is nonzero if we are looking for a destructor. Destructors Returns non-zero, if we find any. Set FNDECL's DECL_VIRTUAL_P, if we
need special treatment because they do not match by name. */ find that it overrides anything.
We check that every function which is overridden, is correctly
overridden. */
tree int
get_matching_virtual (binfo, fndecl, dtorp) look_for_overrides (type, fndecl)
tree binfo, fndecl; tree type, fndecl;
int dtorp;
{ {
tree tmp = NULL_TREE; tree binfo = TYPE_BINFO (type);
tree basebinfos = BINFO_BASETYPES (binfo);
int nbasebinfos = basebinfos ? TREE_VEC_LENGTH (basebinfos) : 0;
int ix;
int found = 0;
if (TREE_CODE (fndecl) == TEMPLATE_DECL) for (ix = 0; ix != nbasebinfos; ix++)
/* In [temp.mem] we have: {
tree basetype = BINFO_TYPE (TREE_VEC_ELT (basebinfos, ix));
if (TYPE_POLYMORPHIC_P (basetype))
found += look_for_overrides_r (basetype, fndecl);
}
return found;
}
A specialization of a member function template does not /* Look in TYPE for virtual functions overridden by FNDECL. Check both
override a virtual function from a base class. */ TYPE itself and its bases. */
return NULL_TREE;
/* Breadth first search routines start searching basetypes static int
of TYPE, so we must perform first ply of search here. */ look_for_overrides_r (type, fndecl)
if (dtorp) tree type, fndecl;
return bfs_walk (binfo, get_virtual_destructor, {
tree_has_any_destructor_p, 0); int ix;
if (DECL_DESTRUCTOR_P (fndecl))
ix = CLASSTYPE_DESTRUCTOR_SLOT;
else else
ix = lookup_fnfields_here (type, DECL_NAME (fndecl));
if (ix >= 0)
{ {
tree drettype, dtypes, btypes, instptr_type; tree fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), ix);
tree baselink, best = NULL_TREE; tree dtypes = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
tree declarator = DECL_NAME (fndecl); tree thistype = DECL_STATIC_FUNCTION_P (fndecl)
if (IDENTIFIER_VIRTUAL_P (declarator) == 0) ? NULL_TREE : TREE_TYPE (TREE_VALUE (dtypes));
return NULL_TREE;
for (; fns; fns = OVL_NEXT (fns))
baselink = get_virtuals_named_this (binfo, declarator); {
if (baselink == NULL_TREE) tree fn = OVL_CURRENT (fns);
return NULL_TREE; tree btypes = TYPE_ARG_TYPES (TREE_TYPE (fn));
drettype = TREE_TYPE (TREE_TYPE (fndecl)); if (!DECL_VIRTUAL_P (fn))
dtypes = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); ;
if (DECL_STATIC_FUNCTION_P (fndecl)) else if (thistype == NULL_TREE)
instptr_type = NULL_TREE;
else
instptr_type = TREE_TYPE (TREE_VALUE (dtypes));
for (; baselink; baselink = next_baselink (baselink))
{
tree tmps;
for (tmps = TREE_VALUE (baselink); tmps; tmps = OVL_NEXT (tmps))
{ {
tmp = OVL_CURRENT (tmps); if (compparms (TREE_CHAIN (btypes), dtypes))
if (! DECL_VINDEX (tmp)) {
continue; /* A static member function cannot match an inherited
virtual member function. */
btypes = TYPE_ARG_TYPES (TREE_TYPE (tmp)); cp_error_at ("`%#D' cannot be declared", fndecl);
if (instptr_type == NULL_TREE) cp_error_at (" since `%#D' declared in base class", fn);
{ return 1;
if (compparms (TREE_CHAIN (btypes), dtypes)) }
/* Caller knows to give error in this case. */ }
return tmp; else
return NULL_TREE; {
} if (/* The first parameter is the `this' parameter,
which has POINTER_TYPE, and we can therefore
if (/* The first parameter is the `this' parameter, safely use TYPE_QUALS, rather than
which has POINTER_TYPE, and we can therefore
safely use TYPE_QUALS, rather than
CP_TYPE_QUALS. */ CP_TYPE_QUALS. */
(TYPE_QUALS (TREE_TYPE (TREE_VALUE (btypes))) (TYPE_QUALS (TREE_TYPE (TREE_VALUE (btypes)))
== TYPE_QUALS (instptr_type)) == TYPE_QUALS (thistype))
&& compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes))) && compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes)))
{ {
check_final_overrider (fndecl, tmp); /* It's definitely virtual, even if not explicitly set. */
DECL_VIRTUAL_P (fndecl) = 1;
/* FNDECL overrides this function. We continue to check_final_overrider (fndecl, fn);
check all the other functions in order to catch
errors; it might be that in some other baseclass return 1;
a virtual function was declared with the same }
parameter types, but a different return type. */
best = tmp;
}
} }
} }
return best;
} }
/* We failed to find one declared in this class. Look in its bases. */
return look_for_overrides (type, fndecl);
} }
/* A queue function for dfs_walk that skips any nonprimary virtual /* A queue function for dfs_walk that skips any nonprimary virtual
...@@ -2320,23 +2239,6 @@ get_pure_virtuals (type) ...@@ -2320,23 +2239,6 @@ get_pure_virtuals (type)
} }
} }
} }
static tree
next_baselink (baselink)
tree baselink;
{
tree tmp = TREE_TYPE (baselink);
baselink = TREE_CHAIN (baselink);
while (tmp)
{
/* @@ does not yet add previous base types. */
baselink = tree_cons (TREE_PURPOSE (tmp), TREE_VALUE (tmp),
baselink);
TREE_TYPE (baselink) = TREE_TYPE (tmp);
tmp = TREE_CHAIN (tmp);
}
return baselink;
}
/* DEPTH-FIRST SEARCH ROUTINES. */ /* DEPTH-FIRST SEARCH ROUTINES. */
......
2000-12-05 Nathan Sidwell <nathan@codesourcery.com> 2000-12-05 Nathan Sidwell <nathan@codesourcery.com>
* g++.old-deja/g++.h/spec6.C: Remove some of the XFAILS.
* g++.old-deja/g++.other/virtual10.C: New test.
2000-12-05 Nathan Sidwell <nathan@codesourcery.com>
* g++.old-deja/g++.mike/pmf5.C: Remove test. * g++.old-deja/g++.mike/pmf5.C: Remove test.
2000-12-05 Richard Henderson <rth@redhat.com> 2000-12-05 Richard Henderson <rth@redhat.com>
......
...@@ -92,7 +92,7 @@ struct A ...@@ -92,7 +92,7 @@ struct A
virtual void wobble(int) throw(E *); // ERROR - overriding virtual void wobble(int) throw(E *); // ERROR - overriding
virtual void wabble(int) throw(E *); virtual void wabble(int) throw(E *);
virtual void wubble(int) throw(E *, H *); virtual void wubble(int) throw(E *, H *);
virtual ~A() throw(); // ERROR - overriding XFAIL virtual ~A() throw(); // ERROR - overriding
}; };
struct B : A struct B : A
...@@ -133,9 +133,7 @@ struct C : A, A1 ...@@ -133,9 +133,7 @@ struct C : A, A1
struct D : A, A1 struct D : A, A1
{ {
// The xfail here is because we don't have the check in the right place to virtual ~D() throw(int); // ERROR - looser throw - A::~A()
// catch dtor failings.
virtual ~D() throw(int); // ERROR - looser throw - A::~A() - XFAIL
}; };
// [except.spec] 5, types shall not be defined in exception specifiers // [except.spec] 5, types shall not be defined in exception specifiers
......
// Build don't link:
// Copyright (C) 2000 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 14 Nov 2000 <nathan@codesourcery.com>
// We failed to spot a static member which overrode a virtual
struct A
{
virtual int foo (char);
static int foo ();
virtual int foo (int); // ERROR - this function
static int foo (float);
virtual int foo (double);
};
struct B : A
{
static int foo (int); // ERROR - cannot override
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment