Browse Source

Merge pull request #77 from ddobrev/master

Properties
pull/78/head
João Matos 12 years ago
parent
commit
5d436f1b48
  1. 2
      src/AST/Class.cs
  2. 36
      src/AST/Property.cs
  3. 3
      src/Generator/Driver.cs
  4. 5
      src/Generator/Generator.lua
  5. 91
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  6. 2
      src/Generator/Passes/FindSymbolsPass.cs
  7. 5
      src/Generator/Passes/GenerateAbstractImplementationsPass.cs
  8. 245
      src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs
  9. 12
      src/Generator/Passes/MultipleInheritancePass.cs
  10. 12
      src/Generator/Passes/RenamePass.cs
  11. 8828
      src/Generator/Passes/verbs.txt
  12. 23
      tests/CSharpTemp/CSharpTemp.Tests.cs
  13. 30
      tests/CSharpTemp/CSharpTemp.cpp
  14. 1
      tests/CSharpTemp/CSharpTemp.cs
  15. 29
      tests/CSharpTemp/CSharpTemp.h

2
src/AST/Class.cs

@ -231,7 +231,7 @@ namespace CppSharp.AST @@ -231,7 +231,7 @@ namespace CppSharp.AST
public Property GetRootBaseProperty(Property @override, bool onlyFirstBase = false)
{
return (from @base in Bases
where !onlyFirstBase || !@base.Class.IsInterface
where (!onlyFirstBase || !@base.Class.IsInterface) && @base.IsClass
let baseProperty = (
from property in @base.Class.Properties
where

36
src/AST/Property.cs

@ -28,6 +28,42 @@ namespace CppSharp.AST @@ -28,6 +28,42 @@ namespace CppSharp.AST
public QualifiedType QualifiedType { get; set; }
public bool IsStatic
{
get
{
return (GetMethod != null && GetMethod.IsStatic) ||
(SetMethod != null && SetMethod.IsStatic);
}
}
public bool IsPure
{
get
{
return (GetMethod != null && GetMethod.IsPure) ||
(SetMethod != null && SetMethod.IsPure);
}
}
public bool IsVirtual
{
get
{
return (GetMethod != null && GetMethod.IsVirtual) ||
(SetMethod != null && SetMethod.IsVirtual);
}
}
public bool IsOverride
{
get
{
return (GetMethod != null && GetMethod.IsOverride) ||
(SetMethod != null && SetMethod.IsOverride);
}
}
public Method GetMethod { get; set; }
public Method SetMethod { get; set; }

3
src/Generator/Driver.cs

@ -158,6 +158,8 @@ namespace CppSharp @@ -158,6 +158,8 @@ namespace CppSharp
TranslationUnitPasses.AddPass(new MultipleInheritancePass());
TranslationUnitPasses.AddPass(new ParamTypeToInterfacePass());
}
if (Options.GenerateProperties)
TranslationUnitPasses.AddPass(new GetterSetterToPropertyAdvancedPass());
}
public void ProcessCode()
@ -288,6 +290,7 @@ namespace CppSharp @@ -288,6 +290,7 @@ namespace CppSharp
public bool GenerateVirtualTables;
public bool GenerateAbstractImpls;
public bool GenerateInterfacesForMultipleInheritance;
public bool GenerateProperties;
public bool GenerateInternalImports;
public string IncludePrefix;
public bool WriteOnlyWhenChanged;

5
src/Generator/Generator.lua

@ -4,7 +4,10 @@ project "CppSharp.Generator" @@ -4,7 +4,10 @@ project "CppSharp.Generator"
language "C#"
location "."
files { "**.cs", "**.bmp", "**.resx", "**.config" }
files { "**.cs", "**.bmp", "**.resx", "**.config", "**verbs.txt" }
excludes { "Filter.cs" }
links { "System", "System.Core", "CppSharp.AST", "CppSharp.Parser" }
configuration '**verbs.txt'
buildaction "Embed"

91
src/Generator/Generators/CSharp/CSharpTextTemplate.cs

@ -784,7 +784,6 @@ namespace CppSharp.Generators.CSharp @@ -784,7 +784,6 @@ namespace CppSharp.Generators.CSharp
{
PushBlock(CSharpBlockKind.Method);
WriteLine("set");
WriteStartBraceIndent();
var param = new Parameter
{
@ -801,7 +800,14 @@ namespace CppSharp.Generators.CSharp @@ -801,7 +800,14 @@ namespace CppSharp.Generators.CSharp
if (decl is Function)
{
var function = decl as Function;
if (function.IsPure && Driver.Options.GenerateAbstractImpls)
{
Write("; ");
PopBlock(NewLineKind.BeforeNextBlock);
return;
}
WriteStartBraceIndent();
if (function.Parameters.Count == 0)
throw new NotSupportedException("Expected at least one parameter in setter");
@ -809,6 +815,14 @@ namespace CppSharp.Generators.CSharp @@ -809,6 +815,14 @@ namespace CppSharp.Generators.CSharp
var method = function as Method;
if (method != null && method.OperatorKind == CXXOperatorKind.Subscript)
{
if (method.IsOverride && method.IsSynthetized)
{
GenerateVirtualTableFunctionCall(function, @class);
}
else
{
if (method.OperatorKind == CXXOperatorKind.Subscript)
{
GenerateIndexerSetter(returnType, method);
}
@ -818,8 +832,16 @@ namespace CppSharp.Generators.CSharp @@ -818,8 +832,16 @@ namespace CppSharp.Generators.CSharp
GenerateInternalFunctionCall(function, parameters);
}
}
}
else
{
var parameters = new List<Parameter> { param };
GenerateInternalFunctionCall(function, parameters);
}
}
else if (decl is Field)
{
WriteStartBraceIndent();
var field = decl as Field;
WriteLine("var {0} = (Internal*){1}.ToPointer();",
@ -865,12 +887,26 @@ namespace CppSharp.Generators.CSharp @@ -865,12 +887,26 @@ namespace CppSharp.Generators.CSharp
where T : Declaration, ITypedDecl
{
PushBlock(CSharpBlockKind.Method);
WriteLine("get");
WriteStartBraceIndent();
Write("get");
if (decl is Function)
{
var function = decl as Function;
if (function.IsPure && Driver.Options.GenerateAbstractImpls)
{
Write("; ");
PopBlock(NewLineKind.BeforeNextBlock);
return;
}
NewLine();
WriteStartBraceIndent();
Method method = function as Method;
if (method != null && method.IsOverride && method.IsSynthetized)
{
GenerateVirtualTableFunctionCall(function, @class);
}
else
{
bool isPrimitiveIndexer = function.OperatorKind == CXXOperatorKind.Subscript &&
function.ReturnType.Type.IsPointerToPrimitiveType();
if (isPrimitiveIndexer)
@ -879,8 +915,11 @@ namespace CppSharp.Generators.CSharp @@ -879,8 +915,11 @@ namespace CppSharp.Generators.CSharp
if (isPrimitiveIndexer)
TypePrinter.PopContext();
}
}
else if (decl is Field)
{
NewLine();
WriteStartBraceIndent();
var field = decl as Field;
WriteLine("var {0} = (Internal*){1}.ToPointer();",
@ -905,6 +944,8 @@ namespace CppSharp.Generators.CSharp @@ -905,6 +944,8 @@ namespace CppSharp.Generators.CSharp
}
else if (decl is Variable)
{
NewLine();
WriteStartBraceIndent();
var @var = decl as Variable;
var libSymbol = GetDeclarationLibrarySymbol(@var);
@ -990,10 +1031,22 @@ namespace CppSharp.Generators.CSharp @@ -990,10 +1031,22 @@ namespace CppSharp.Generators.CSharp
type = ((PointerType) prop.Type).Pointee;
if (prop.ExplicitInterfaceImpl == null)
WriteLine("{0}{1} {2}", Helpers.GetAccess(prop.Access),
type, GetPropertyName(prop));
{
Write(Helpers.GetAccess(prop.Access));
if (prop.IsStatic)
Write("static ");
if (prop.IsOverride)
Write("override ");
else if (prop.IsPure && Driver.Options.GenerateAbstractImpls)
Write("abstract ");
else if (prop.IsVirtual)
Write("virtual ");
WriteLine("{0} {1}", type, GetPropertyName(prop));
}
else
{
WriteLine("{0} {1}.{2}", type, prop.ExplicitInterfaceImpl.Name, GetPropertyName(prop));
}
WriteStartBraceIndent();
if (prop.Field != null)
@ -1044,7 +1097,9 @@ namespace CppSharp.Generators.CSharp @@ -1044,7 +1097,9 @@ namespace CppSharp.Generators.CSharp
public void GenerateVTable(Class @class)
{
var entries = VTables.GatherVTableMethodEntries(@class);
entries = entries.Where(entry => !entry.Method.Ignore).ToList();
entries = entries.Where(e => !e.Method.Ignore ||
@class.Properties.Any(p => !p.Ignore &&
(p.GetMethod == e.Method || p.SetMethod == e.Method))).ToList();
if (entries.Count == 0)
return;
@ -1203,7 +1258,14 @@ namespace CppSharp.Generators.CSharp @@ -1203,7 +1258,14 @@ namespace CppSharp.Generators.CSharp
if (hasReturn)
Write("var _ret = ");
if (method.IsGenerated)
{
WriteLine("target.{0}({1});", SafeIdentifier(method.Name), string.Join(", ", marshals));
}
else
{
InvokeProperty(method, marshals);
}
// TODO: Handle hidden structure return types.
@ -1233,6 +1295,23 @@ namespace CppSharp.Generators.CSharp @@ -1233,6 +1295,23 @@ namespace CppSharp.Generators.CSharp
}
}
private void InvokeProperty(Declaration method, IEnumerable<string> marshals)
{
var property = ((Class) method.Namespace).Properties.FirstOrDefault(
p => p.GetMethod == method);
if (property == null)
{
property = ((Class) method.Namespace).Properties.First(
p => p.SetMethod == method);
WriteLine("target.{0} = {1};", SafeIdentifier(property.Name),
string.Join(", ", marshals));
}
else
{
WriteLine("target.{0};", SafeIdentifier(property.Name));
}
}
private void GenerateVTableMethodDelegates(Class @class, Method method)
{
PushBlock(CSharpBlockKind.VTableDelegate);

2
src/Generator/Passes/FindSymbolsPass.cs

@ -12,7 +12,7 @@ namespace CppSharp.Passes @@ -12,7 +12,7 @@ namespace CppSharp.Passes
var mangledDecl = decl as IMangledDecl;
var method = decl as Method;
if (mangledDecl != null && !(method != null && method.IsPure) &&
if (mangledDecl != null && !(method != null && (method.IsPure || method.IsSynthetized)) &&
!VisitMangledDeclaration(mangledDecl))
{
decl.ExplicityIgnored = true;

5
src/Generator/Passes/GenerateAbstractImplementationsPass.cs

@ -57,7 +57,8 @@ namespace CppSharp.Passes @@ -57,7 +57,8 @@ namespace CppSharp.Passes
{
Name = abstractMethod.Name + "Delegate",
QualifiedType = abstractMethod.GetFunctionType(),
IgnoreFlags = abstractMethod.IgnoreFlags
IgnoreFlags = abstractMethod.IgnoreFlags,
Namespace = internalImpl
};
internalImpl.Typedefs.Add(@delegate);
}
@ -79,7 +80,7 @@ namespace CppSharp.Passes @@ -79,7 +80,7 @@ namespace CppSharp.Passes
var internalImpl = new Class
{
Name = @class.Name + "Internal",
Access = AccessSpecifier.Private,
Access = @class.Access,
Namespace = @class.Namespace
};
var @base = new BaseClassSpecifier { Type = new TagType(@class) };

245
src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs

@ -0,0 +1,245 @@ @@ -0,0 +1,245 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using CppSharp.AST;
namespace CppSharp.Passes
{
class GetterSetterToPropertyAdvancedPass : TranslationUnitPass
{
// collect all types of methods first to be able to match pairs and detect virtuals and overrides;
// (a property needs to) be virtual or an override if either of its constituent methods are such)
private readonly List<Method> setters = new List<Method>();
private readonly List<Method> setMethods = new List<Method>();
private readonly List<Method> nonSetters = new List<Method>();
private readonly HashSet<Method> getters = new HashSet<Method>();
private static readonly HashSet<string> verbs = new HashSet<string>();
static GetterSetterToPropertyAdvancedPass()
{
LoadVerbs();
}
private static void LoadVerbs()
{
using (var resourceStream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream("CppSharp.Generator.Passes.verbs.txt"))
{
using (StreamReader streamReader = new StreamReader(resourceStream))
while (!streamReader.EndOfStream)
verbs.Add(streamReader.ReadLine());
}
}
public GetterSetterToPropertyAdvancedPass()
{
Options.VisitClassFields = false;
Options.VisitClassProperties = false;
Options.VisitNamespaceEnums = false;
Options.VisitNamespaceTemplates = false;
Options.VisitNamespaceTypedefs = false;
Options.VisitNamespaceEvents = false;
Options.VisitNamespaceVariables = false;
Options.VisitFunctionParameters = false;
Options.VisitTemplateArguments = false;
}
public override bool VisitTranslationUnit(TranslationUnit unit)
{
bool result = base.VisitTranslationUnit(unit);
GenerateProperties();
return result;
}
public override bool VisitMethodDecl(Method method)
{
if (!method.IsConstructor && !method.IsDestructor && !method.IsOperator &&
!method.Ignore)
DistributeMethod(method);
return base.VisitMethodDecl(method);
}
public void GenerateProperties()
{
GenerateProperties(setters, false);
GenerateProperties(setMethods, true);
foreach (Method getter in
from getter in getters
where getter.IsGenerated &&
((Class) getter.Namespace).Methods.All(m => m == getter || m.Name != getter.Name)
select getter)
{
// Make it a read-only property
GenerateProperty(getter.Namespace, getter);
}
}
private void GenerateProperties(IEnumerable<Method> settersToUse, bool readOnly)
{
foreach (var group in settersToUse.GroupBy(m => m.Namespace))
{
foreach (var setter in group)
{
Class type = (Class) setter.Namespace;
StringBuilder nameBuilder = new StringBuilder(setter.Name.Substring(3));
if (char.IsLower(setter.Name[0]))
nameBuilder[0] = char.ToLowerInvariant(nameBuilder[0]);
string afterSet = nameBuilder.ToString();
foreach (var getter in nonSetters.Where(m => m.Namespace == type))
{
string name = GetPropertyName(getter.Name);
if (string.Compare(name, afterSet, StringComparison.OrdinalIgnoreCase) == 0 &&
getter.ReturnType == setter.Parameters[0].QualifiedType &&
!type.Methods.Any(
m =>
m != getter &&
string.Compare(name, m.Name, StringComparison.OrdinalIgnoreCase) == 0))
{
GenerateProperty(getter.Namespace, getter, readOnly ? null : setter);
goto next;
}
}
Property baseVirtualProperty = type.GetRootBaseProperty(new Property { Name = afterSet });
if (!type.IsInterface && baseVirtualProperty != null)
{
bool isReadOnly = baseVirtualProperty.SetMethod == null;
GenerateProperty(setter.Namespace, baseVirtualProperty.GetMethod,
readOnly || isReadOnly ? null : setter);
}
next:
;
}
}
foreach (Method nonSetter in nonSetters)
{
Class type = (Class) nonSetter.Namespace;
string name = GetPropertyName(nonSetter.Name);
Property baseVirtualProperty = type.GetRootBaseProperty(new Property { Name = name });
if (!type.IsInterface && baseVirtualProperty != null)
{
bool isReadOnly = baseVirtualProperty.SetMethod == null;
if (readOnly == isReadOnly)
{
GenerateProperty(nonSetter.Namespace, nonSetter,
readOnly ? null : baseVirtualProperty.SetMethod);
}
}
}
}
private static void GenerateProperty(DeclarationContext context, Method getter, Method setter = null)
{
Class type = (Class) context;
if (type.Properties.All(
p => string.Compare(getter.Name, p.Name, StringComparison.OrdinalIgnoreCase) != 0 ||
p.ExplicitInterfaceImpl != getter.ExplicitInterfaceImpl))
{
Property property = new Property();
property.Name = GetPropertyName(getter.Name);
property.Namespace = type;
property.QualifiedType = getter.ReturnType;
if (getter.IsOverride || (setter != null && setter.IsOverride))
{
Property baseVirtualProperty = type.GetRootBaseProperty(property);
if (baseVirtualProperty.SetMethod == null)
setter = null;
foreach (Method method in type.Methods.Where(m => m.Name == property.Name && m.Parameters.Count > 0))
method.Name = "get" + method.Name;
}
property.GetMethod = getter;
property.SetMethod = setter;
property.ExplicitInterfaceImpl = getter.ExplicitInterfaceImpl;
if (property.ExplicitInterfaceImpl == null && setter != null)
{
property.ExplicitInterfaceImpl = setter.ExplicitInterfaceImpl;
}
if (getter.Comment != null)
{
var comment = new RawComment();
comment.Kind = getter.Comment.Kind;
comment.BriefText = getter.Comment.BriefText;
comment.Text = getter.Comment.Text;
comment.FullComment = new FullComment();
comment.FullComment.Blocks.AddRange(getter.Comment.FullComment.Blocks);
if (setter != null && setter.Comment != null)
{
comment.BriefText += Environment.NewLine + setter.Comment.BriefText;
comment.Text += Environment.NewLine + setter.Comment.Text;
comment.FullComment.Blocks.AddRange(setter.Comment.FullComment.Blocks);
}
property.Comment = comment;
}
type.Properties.Add(property);
getter.IsGenerated = false;
if (setter != null)
setter.IsGenerated = false;
}
}
private static string GetPropertyName(string name)
{
if (GetFirstWord(name) == "get")
{
if (char.IsLower(name[0]))
{
if (name.Length == 4)
{
return char.ToLowerInvariant(
name[3]).ToString(CultureInfo.InvariantCulture);
}
return char.ToLowerInvariant(
name[3]).ToString(CultureInfo.InvariantCulture) +
name.Substring(4);
}
return name.Substring(3);
}
return name;
}
private void DistributeMethod(Method method)
{
if (GetFirstWord(method.Name) == "set" && method.Name.Length > 3 &&
method.ReturnType.Type.IsPrimitiveType(PrimitiveType.Void))
{
if (method.Parameters.Count == 1)
setters.Add(method);
else
setMethods.Add(method);
}
else
{
if (IsGetter(method))
getters.Add(method);
if (method.Parameters.Count == 0)
nonSetters.Add(method);
}
}
private bool IsGetter(Method method)
{
if (method.ReturnType.Type.IsPrimitiveType(PrimitiveType.Void) ||
method.Parameters.Count > 0 || method.IsDestructor)
return false;
var result = GetFirstWord(method.Name);
return (result.Length < method.Name.Length &&
(result == "get" || result == "is" || result == "has")) ||
(result != "to" && result != "new" && !verbs.Contains(result));
}
private static string GetFirstWord(string name)
{
List<char> firstVerb = new List<char>
{
char.ToLowerInvariant(name[0])
};
firstVerb.AddRange(name.Skip(1).TakeWhile(
c => char.IsLower(c) || !char.IsLetterOrDigit(c)));
return new string(firstVerb.ToArray());
}
}
}

12
src/Generator/Passes/MultipleInheritancePass.cs

@ -66,9 +66,15 @@ namespace CppSharp.Passes @@ -66,9 +66,15 @@ namespace CppSharp.Passes
let i = GetInterface(@base, b.Class)
select new BaseClassSpecifier { Type = new TagType(i) });
@interface.Methods.AddRange(@base.Methods.Where(
m => !m.IsConstructor && !m.IsDestructor && !m.IsStatic && !m.Ignore));
@interface.Properties.AddRange(@base.Properties.Where(p => !p.Ignore));
@interface.Methods.AddRange(
from m in @base.Methods
where !m.IsConstructor && !m.IsDestructor && !m.IsStatic && !m.Ignore
select new Method(m) { Namespace = @interface });
@interface.Properties.AddRange(
from property in @base.Properties
where !property.Ignore
select new Property(property) { Namespace = @interface });
if (@interface.Bases.Count == 0)
{

12
src/Generator/Passes/RenamePass.cs

@ -39,6 +39,7 @@ namespace CppSharp.Passes @@ -39,6 +39,7 @@ namespace CppSharp.Passes
if (decl is Enumeration) return true;
if (decl is Property) return true;
if (decl is Event) return true;
if (decl is TypedefDecl) return true;
return false;
}
@ -125,6 +126,14 @@ namespace CppSharp.Passes @@ -125,6 +126,14 @@ namespace CppSharp.Passes
return base.VisitProperty(property);
}
public override bool VisitTypedefDecl(TypedefDecl typedef)
{
if (!Targets.HasFlag(RenameTargets.Delegate))
return false;
return base.VisitTypedefDecl(typedef);
}
public override bool VisitMethodDecl(Method method)
{
if (!Targets.HasFlag(RenameTargets.Method))
@ -173,7 +182,8 @@ namespace CppSharp.Passes @@ -173,7 +182,8 @@ namespace CppSharp.Passes
EnumItem = 1 << 6,
Event = 1 << 7,
Property = 1 << 8,
Any = Function | Method | Parameter | Class | Field | Enum | EnumItem | Event | Property,
Delegate = 1 << 9,
Any = Function | Method | Parameter | Class | Field | Enum | EnumItem | Event | Property | Delegate,
}
/// <summary>

8828
src/Generator/Passes/verbs.txt

File diff suppressed because it is too large Load Diff

23
tests/CSharpTemp/CSharpTemp.Tests.cs

@ -45,19 +45,34 @@ public class CSharpTempTests @@ -45,19 +45,34 @@ public class CSharpTempTests
public void TestMultipleInheritance()
{
Baz baz = new Baz();
Assert.That(baz.method(), Is.EqualTo(1));
Assert.That(baz.method, Is.EqualTo(1));
var bar = (IBar) baz;
Assert.That(bar.method(), Is.EqualTo(2));
Assert.That(bar.method, Is.EqualTo(2));
Assert.That(baz[0], Is.EqualTo(50));
bar[0] = new Foo { A = 1000 };
Assert.That(bar[0].A, Is.EqualTo(1000));
Assert.That(baz.farAwayFunc(), Is.EqualTo(20));
Assert.That(baz.farAwayFunc, Is.EqualTo(20));
Assert.That(baz.takesQux(baz), Is.EqualTo(20));
Assert.That(baz.returnQux().farAwayFunc(), Is.EqualTo(20));
Assert.That(baz.returnQux().farAwayFunc, Is.EqualTo(20));
int cast = baz;
Assert.That(cast, Is.EqualTo(500));
var nested = new Baz.Nested();
int nestedCast = nested;
Assert.That(nestedCast, Is.EqualTo(300));
}
[Test]
public void TestProperties()
{
var proprietor = new Proprietor();
proprietor.value = 20;
Assert.That(proprietor.value, Is.EqualTo(20));
proprietor.prop = 50;
Assert.That(proprietor.prop, Is.EqualTo(50));
var p = new P();
p.value = 20;
Assert.That(p.value, Is.EqualTo(30));
p.prop = 50;
Assert.That(p.prop, Is.EqualTo(150));
}
}

30
tests/CSharpTemp/CSharpTemp.cpp

@ -65,3 +65,33 @@ Baz::operator int() const @@ -65,3 +65,33 @@ Baz::operator int() const
{
return 500;
}
int AbstractProprietor::getValue()
{
return m_value;
}
void AbstractProprietor::setProp(long property)
{
m_property = property;
}
void Proprietor::setValue(int value)
{
m_value = value;
}
long Proprietor::prop()
{
return m_property;
}
void P::setValue(int value)
{
m_value = value + 10;
}
long P::prop()
{
return m_property + 100;
}

1
tests/CSharpTemp/CSharpTemp.cs

@ -13,6 +13,7 @@ namespace CppSharp.Tests @@ -13,6 +13,7 @@ namespace CppSharp.Tests
public override void SetupPasses(Driver driver)
{
driver.Options.GenerateInterfacesForMultipleInheritance = true;
driver.Options.GenerateProperties = true;
}
static class Program

29
tests/CSharpTemp/CSharpTemp.h

@ -63,3 +63,32 @@ struct QByteArrayDataPtr @@ -63,3 +63,32 @@ struct QByteArrayDataPtr
{
QByteArrayData* ptr;
};
class DLL_API AbstractProprietor
{
public:
virtual int getValue();
virtual void setValue(int value) = 0;
virtual long prop() = 0;
virtual void setProp(long prop);
protected:
int m_value;
long m_property;
};
class DLL_API Proprietor : public AbstractProprietor
{
public:
virtual void setValue(int value);
virtual long prop();
};
class DLL_API P : Proprietor
{
public:
virtual void setValue(int value);
virtual long prop();
};

Loading…
Cancel
Save